Skip to content

Add CSV export to RA Management search results#521

Open
kayjoosten wants to merge 2 commits into
mainfrom
feature/issue-498-ra-management-csv-export
Open

Add CSV export to RA Management search results#521
kayjoosten wants to merge 2 commits into
mainfrom
feature/issue-498-ra-management-csv-export

Conversation

@kayjoosten

@kayjoosten kayjoosten commented Jul 21, 2026

Copy link
Copy Markdown

Summary

  • Adds an Export button next to Search on the RA Management page, matching the existing Tokens (Second Factors) page pattern.
  • RaListingService::export() pages through the existing paginated middleware search (no unpaginated export endpoint exists for RA listings) and streams the aggregated results as CSV via a new RaListingExport service.
  • Export filename follows the role filter: ra_export_YYYY-MM-DD, raa_export_YYYY-MM-DD, or ra-raa-export_YYYY-MM-DD when unfiltered.
  • Renames the blank Role filter option to a "RA/RAA" placeholder.
  • export() keeps its own ROLE_RAA authorization check, independent of manage().

Test plan

  • php -l on all changed/new PHP files
  • XML validation of both translation xliff files
  • YAML validation of services.yml
  • Manually verified in a local docker-devconf environment (smoketest mode): logged in as RAA, submitted search with no/RA/RAA role filters, clicked Export each time, confirmed correct filenames and CSV row content/filtering
  • Confirmed a plain RA (no RAA) user cannot access the export button or action
  • Unit tests for ExportRaListingCommand::fromSearchCommand, RaListingService::export, RaListingExport::export (not yet added)

Closes #498

If applied, this commit will let RAA users export the current RA
Management search results as a CSV file, and rename the blank Role
filter option to a descriptive label.

Why is this change needed?
Prior to this change, the RA Management page had no export option,
unlike the existing Tokens (Second Factors) page. Institution admins
had no way to get an offline copy of their RA(A) listing. The Role
filter dropdown also had an unlabeled blank option between "RA" and
"RAA", which was unclear to users.

How does it address the issue?
This change adds an Export button next to Search, following the same
button-group pattern used on the Tokens page. Since RA listings have
no unpaginated export endpoint in the middleware client (unlike Second
Factors), RaListingService::export() pages through the existing
paginated search results and aggregates them before handing off to the
new RaListingExport service, which streams the results as CSV via
fputcsv. The exported filename is derived from the active role filter:
ra_export_YYYY-MM-DD, raa_export_YYYY-MM-DD, or
ra-raa-export_YYYY-MM-DD when no role filter is set. The Role filter's
blank option now shows a "RA/RAA" placeholder instead of being empty.
The export action keeps its own ROLE_RAA authorization check
independent of the search action, so it stays protected even if the
search page's access level changes later. Institution-scoping and
existing authorization boundaries are unchanged.

Links / references:
#498
If applied, this commit will make the CI QA pipeline pass for the RA
Management CSV export feature.

Why is this change needed?
Prior to this change, CI's phpstan step failed on the new export code:
an untyped/uninitialized $actorId property, a stale baseline entry for
a booleanAnd.leftAlwaysTrue error that the buildQuery() refactor already
fixed by making its $roleAtInstitution parameter nullable, unchecked
resource|false returns from fopen() in RaListingExport, a missing
iterable value type on getColumnNames(), and a new getClickedButton()
call on FormInterface that needed the same baseline treatment already
used for the equivalent Second Factors export form.

How does it address the issue?
This change adds a `@var string` docblock to
ExportRaListingCommand::$actorId (matching the existing
ExportRaSecondFactorsCommand convention), removes the now-stale
booleanAnd.leftAlwaysTrue baseline entry for RaListingService, adds a
baseline entry for RaManagementController's getClickedButton() call
mirroring SecondFactorController's, guards the fopen() result in
RaListingExport before using it, and adds a `@return string[]` docblock
to getColumnNames().
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add CSV export functionality to RA Management search results

1 participant