Commit Graph

61568 Commits

Author SHA1 Message Date
Pedro Amorim 3595d2abe8
Bug 37762: (QA follow-up): Address test files QA complaints
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:52 -06:00
Pedro Amorim 353ffe9b7a
Bug 37762: (QA follow-up): Relabel pending requesting agency action
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:51 -06:00
Pedro Amorim bbc4e8050d
Bug 37762: (QA follow-up): Add filters to supply ILL table
Also fix table_settings

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:51 -06:00
Pedro Amorim 926a03b77c
Bug 37762: (QA follow-up): Fix supplying agency request ID label
Also clean-up redundant code pending ra action

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:50 -06:00
Pedro Amorim 8b09ae352e
Bug 37762: (QA follow-up): Add placeholder to callback_endpoint
In requesting agency configuration page

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:50 -06:00
Pedro Amorim 3c75ae097c
Bug 37762: (QA follow-up): Add ShippedReturn support action type
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:49 -06:00
Pedro Amorim 19f7470b40
Bug 37762: (QA follow-up): Add real requesting agency request ID to ISO message
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:49 -06:00
Pedro Amorim 23c85e598e
Bug 37762: (QA follow-up): Add loading while action is processing
This also prevents clicking other action buttons while an action is midflight

cypress run --spec t/cypress/integration/ILL/SupplyingRequests.ts

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:48 -06:00
Pedro Amorim 1064b56e94
Bug 37762: (QA follow-up): Add message with timestamp +1
Instead of waiting a real 1 second

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:48 -06:00
Pedro Amorim 86c479edee
Bug 37762: Add additional tests
cypress run --spec t/cypress/integration/ILL/SupplyingRequests.ts
cypress run --spec t/cypress/integration/ILL/RequestingAgencies.ts
prove t/db_dependent/Koha/ILL/ISO18626/Request.t

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:47 -06:00
Pedro Amorim 79496466cb
Bug 37762: (QA follow-up): Fix checkout for bib-level holds
This will now find the corresponding ISO18626 request and update it accordingly when a check-out happens.

Use-case this is addressing:
1. Place an item-level hold for Henry
2. Check-in that item e.g. 39999000003130 (make it waiting)
3. Create a new ISO18626 request and 'Search to hold', place a bib-level hold on the same bib as above (for patron Walker)
4. Check-out the item from 2. 39999000003130 to Walker
5. Confirm an ISO18626 message input is shown and that the respective ISO18626 request is updated to 'Loaned' once the check-out happens (i.e. override Henry's hold).

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:47 -06:00
Pedro Amorim 98bd736dac
Bug 37762: (QA follow-up): Fix rendering regular holds in table
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:46 -06:00
Pedro Amorim f036c92ec0
Bug 37762: Send message back to requesting agency
This commit applies changes to V1.pm to be able to utilize the same XML methods.
We're also updating tests to reflect this new functionality.

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:46 -06:00
Pedro Amorim ae3b70b66b
Bug 37762: SupplyingResource updates
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:45 -06:00
Pedro Amorim 468a4b73e8
Bug 37762: VueJS framework: Add biblio and checkout API clients
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:45 -06:00
Pedro Amorim c32d08e560
Bug 37762: Catalogue: Hook to biblios
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:44 -06:00
Pedro Amorim db7854682e
Bug 37762: Circulation: Hook to checkouts/checkins
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:43 -06:00
Pedro Amorim 950c9ccb96
Bug 37762: Circulation: Hook to holds
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:43 -06:00
Pedro Amorim 1d6fb7f57d
Bug 37762: Hook to holds preparation: DRY holdfor and searchToOrder
In preparation to implement 'hold for supply ILL'
This DRYs the existing functionality, meaning the new similar functionality will only be added once in the Controller::Catalogue

IMPORTANT:
The following command must only return occurrences in
Koha::Controller::Catalogue before this is pushed to main:
git grep "\->cookie(\"holdfor\")"

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:42 -06:00
Pedro Amorim 87961beb4d
Bug 37762: Bugfix: Display relationshipSelect
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:42 -06:00
Pedro Amorim 8e87fae1cc
Bug 37762: ISO18626 KOHA classes
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:41 -06:00
Pedro Amorim 2f17713637
Bug 37762: ISO18626 Koha DB changes
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:41 -06:00
Pedro Amorim 29c1a17da5
Bug 37762: Add ISO18626 tests
prove t/db_dependent/api/v1/iso18626/request.t
prove t/db_dependent/api/v1/iso18626/requesting_agencies.t

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:40 -06:00
Pedro Amorim f9b9bc77b2
Bug 37762: ISO18626 REST API specs
Reference:
https: //illtransactions.org/schemas/ISO-18626-2021-2.xsd
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:40 -06:00
Pedro Amorim 55fa4609fa
Bug 37762: REST API: Convert XML payload to JSON for swagger definition validation
Convert JSON response to XML if header content_type: application/xml

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:39 -06:00
Pedro Amorim 2a1fa8d091
Bug 37762: Vuejs sysprefs store: Allow fetching multiple sys pref values
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:39 -06:00
Pedro Amorim 6dab32ee02
Bug 37762: VueJS ILL Module
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:38 -06:00
Pedro Amorim b307692fb1
Bug 37762: PatronAutoComplete: VueJS framework: Add patronAutoComplete attribute type
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:38 -06:00
Pedro Amorim df37e571d0
Bug 37762: PatronAutoComplete prep: Abstract rendering of selected patron
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:37 -06:00
Pedro Amorim 48783f8477
Bug 37762: PatronAutoComplete prep: Add on remove callback to patron_autocomplete
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:36 -06:00
Pedro Amorim 7374325216
Bug 37762: PatronAutoComplete prep: Allow additional filters in patron_autocomplete
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:36 -06:00
Pedro Amorim 30161380a9
Bug 37762: Fix confirmation button CSS class in confirmation modal
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:35 -06:00
Pedro Amorim bc0ae34098
Bug 37762: VueJS framework: Add attribute.format check in empty groups check
This keeps the same functionality as before, i.e. hide the whole group
if all attributes within are empty. However it now also checks for
'format' as some resources may want to format the display of empty attributes.

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:35 -06:00
Pedro Amorim 66d7845764
Bug 37762: VueJS framework: Add possibility of external navigation item
e.g.:

{
    path: "/cgi-bin/koha/ill/ill-requests.pl",
    title: $__("Requests"),
    icon: "fa fa-download",
    is_external: true,
    is_navigation_item: true,
},

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:34 -06:00
Pedro Amorim b4fe2b92dd
Bug 37762: VueJS framework: Add 'name' to moduleDashboard
This is required to differentiate between selected widgets on different module dashboards i.e. ERM vs ILL

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:34 -06:00
Pedro Amorim a2c13377ed
Bug 37762: VueJS framework: Toolbarbutton spacing to consider different css classes
There's no spacing currently, but it's not obvious as the current style
has the same background color as the body.
This adds spacing so even if some buttons have different colors (e.g.
primary or danger) all buttons are spaced correctly.

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:33 -06:00
Pedro Amorim a40fa90d6a
Bug 37762: VueJS framework: updateConfirmationDialogInputs
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:33 -06:00
Pedro Amorim 91b4780074
Bug 37762: VueJS framework: Add update event to v-select FormElement
The existing 'selected' event only fires when something is selected, it does not fire when a selection is unselected. onUpdated fires for both.

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:32 -06:00
Pedro Amorim 903da26fe4
Bug 37762: VueJS framework: Fix tooltip within modal dialog
Without this, the tooltip is behind the modal thus invisible

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:32 -06:00
Pedro Amorim bd9dc920de
Bug 37762: VueJS framework: Allow styling v-select dropdown
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:31 -06:00
Pedro Amorim 3e756390cb
Bug 37762: VueJS framework: Update width of inputs inside modal dialog
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:31 -06:00
Pedro Amorim 38b38bdce6
Bug 37762: VueJS framework: Add cssClass consideration to link buttons
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:30 -06:00
Pedro Amorim 675dd1cac0
Bug 37762: VueJS framework: Add patch to http-client.js
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:29 -06:00
Matt Blenkinsop 9e420632e7
Bug 37762: Allow FormElement to accept hidden inputs
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:23 -06:00
Martin Renvoize 6f62a8fe30
Bug 41919: Limit number of current reports a single user can run simultaneously
Building on bug 41918, it would be good to limit the number of reports
a given user can run at a time. This control is config-file based as
it is tied to the server resources provided by the administrator.

Adds a new koha-conf.xml option total_running_reports_per_user_limit
(0 = disabled). When the configured limit is reached, the user is told
"You have too many reports running at the moment. Please wait for some
of them to finish before running this report again."

Note on implementation: the original patch on bz (attachment 198034)
performed a second pre-flight Koha::Reports->running call in
reports/guided_reports.pl. The bug 41918 QA follow-ups already pushed
the duplicate-running guard into Koha::Report::prep_report so it would
fire across the staff UI, svc/report and opac/svc/report. This patch
extends that same model-layer architecture rather than reintroducing
controller-layer enforcement:

- New Koha::Exceptions::Report::TotalRunning subclass of
  Koha::Exceptions::Report.
- prep_report now performs a second check after the duplicate one and
  throws TotalRunning when the user has total_running_reports_per_user_limit
  reports of any kind already in flight.
- All three callers (guided_reports.pl, svc/report, opac/svc/report)
  catch the new exception alongside DuplicateRunning, mapping it to a
  new template error key total_running_reports_limit_exceeded for the
  staff UI and a JSON {error: total_running_reports_limit_exceeded}
  with HTTP 429 for the JSON endpoints.

Test Plan:
1) Set total_running_reports_per_user_limit to 3 in your koha-conf.xml.
2) Create 3 long-running reports like:
   SELECT COUNT(*) FROM items i1 JOIN items i2 JOIN items i3 JOIN items i4 JOIN items i5 JOIN items i6
3) Run each report in turn by opening a new tab, browsing to the
   reports module, and choosing to run that report.
4) Note the first three continue to run, but a fourth attempt gives
   the new "too many reports running" alert in the staff UI.
5) Repeat against /cgi-bin/koha/svc/report?id=N and confirm an HTTP
   429 response with JSON {error: total_running_reports_limit_exceeded}.
6) Set total_running_reports_per_user_limit back to 0 and confirm
   normal behaviour resumes.
7) prove t/db_dependent/Koha/Reports.t -> 13 tests pass, including a
   new subtest for TotalRunning.

Signed-off-by: Alex Carver [Acerock7] <alex@rcls.org>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-07 07:56:21 -06:00
Lucas Gass 158f0bbef5
Bug 41918: (RM follow-up) Add POD
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-07 07:56:21 -06:00
Martin Renvoize 4227119b63
Bug 41918: (QA follow-up) Catch DuplicateRunning in op=export path
The CSV/tab export branch (op=export) of reports/guided_reports.pl
calls Koha::Report::prep_report just like the op=run branch and the
two svc/report endpoints, but unlike the others it had no eval/catch
around the call. The QA follow-ups that pushed enforcement into the
model layer therefore left this one path emitting a 500 (uncaught
Koha::Exceptions::Report::DuplicateRunning) when the configured
duplicate-running limit is exceeded.

Wrap the call in the same pattern as svc/report: on
DuplicateRunning return HTTP 429 Too Many Requests with a plain-text
body explaining the situation. Plain text rather than the staff
template because op=export sets file-download headers and the user is
expecting either the file or an error - we don't have a sensible way
to fall back into the report-run template from this branch.

The CLI runners (misc/cronjobs/runreport.pl, misc/export_records.pl)
still bypass prep_report and therefore the limit, which is intended:
scheduled / batch jobs should not be subject to user-quota
enforcement.

Test plan:
1) Set duplicate_running_reports_per_user_limit=1 in koha-conf.xml,
   restart_all.
2) Start a long-running report from the staff UI.
3) While it is running, navigate to op=export with the same report
   id (eg. via the "Export" button).
4) Before the patch: 500 with a stack trace in the logs.
   After the patch: 429 with body "This report is already running.
   Please wait for it to finish before running it again."
5) Set the limit back to 0 and confirm exports work normally again.

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-07 07:56:20 -06:00
Martin Renvoize 63af0dd4fd
Bug 41918: (QA follow-up) Scope processlist query to the current DB user
Koha::Reports->running queries information_schema.processlist. Without
the PROCESS privilege MariaDB/MySQL already restrict the view to the
caller's own threads, so the previous code worked correctly on stock
deployments. However, if a site has granted broader privileges (eg. a
shared MariaDB server where the Koha DB user happens to also have
PROCESS, or a custom role) the query would happily count threads
belonging to other database users - another Koha instance, a reporting
tool, or any unrelated application sharing the server.

Add an explicit

    user = SUBSTRING_INDEX(CURRENT_USER(), '@', 1)

clause so the query is always scoped to the connection's MySQL user,
regardless of what privileges that user has been granted. The
processlist.user column holds just the username with no host, so we
strip the '@host' off CURRENT_USER() before comparing.

The new clause has no bind parameters - it is a constant per
connection - so the existing parameterised-bind assertions in the
running subtest still hold. A small additional assertion verifies the
clause is present in the SQL text.

Test plan:
1) prove t/db_dependent/Koha/Reports.t (now 12 tests, all pass).
2) Optional: in a multi-tenant MariaDB, grant PROCESS to the Koha DB
   user, start a long query as a different DB user with the marker
   /* { saved_sql.id: 1 } { user_id: 1 } */ in its info, then call
   Koha::Reports->running. Confirm the foreign thread is NOT counted.

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-07 07:56:20 -06:00
Martin Renvoize 7d12dac853
Bug 41918: (QA follow-up) Enforce duplicate-running limit in the model
The previous patches enforced duplicate_running_reports_per_user_limit
only in reports/guided_reports.pl. Two other code paths run saved SQL
reports for an authenticated user and bypassed the guard entirely:

- svc/report (staff JSON endpoint, eg. used for chart widgets and any
  caller hitting /cgi-bin/koha/svc/report?id=N directly)
- opac/svc/report (OPAC JSON endpoint)

A user who hit their staff-UI limit could still spawn additional copies
of the same long-running report via either svc endpoint, defeating the
guard.

Push the check into Koha::Report::prep_report itself, which is the one
function all three callers go through. When the limit is reached
prep_report now throws a new Koha::Exceptions::Report::DuplicateRunning
(carrying report_id, user_id and the configured limit). The guided
reports CGI catches it and re-renders the existing "report is already
running" alert; both svc/report endpoints catch it and return HTTP 429
Too Many Requests with a JSON { error: "duplicate_running_report" }
payload.

Notes:
- The pre-flight Koha::Reports->running call is removed from the
  guided-reports CGI; the model now owns that policy and the
  controller is just rendering. The TOCTOU window remains identical
  in size and is the same intentional trade-off as before.
- Limit=0 (the default) and absent userenv both bypass the check, so
  CLI cronjobs (misc/cronjobs/runreport.pl) and direct DB users are
  unaffected.

Test plan:
1) prove t/db_dependent/Koha/Reports.t - now includes a new subtest
   covering limit=0 (lives), under limit (lives) and at limit (throws
   Koha::Exceptions::Report::DuplicateRunning).
2) Set duplicate_running_reports_per_user_limit=1 in koha-conf.xml,
   restart_all.
3) Open a long-running report in two staff tabs - second tab shows
   the "report is already running" alert (unchanged behaviour).
4) While one run is in flight, hit /cgi-bin/koha/svc/report?id=N as
   the same user - now returns HTTP 429 with the JSON error payload
   (previously: ran a second copy of the query).
5) Same check on /cgi-bin/koha/opac/svc/report?id=N.

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-07 07:56:19 -06:00
Martin Renvoize b4d9063368
Bug 41918: (QA follow-up) Document SQL marker contract and TOCTOU window
Two small documentation improvements following on from the duplicate-
running guard:

- Koha::Report::prep_report now spells out the tracking-comment format
  in its POD. Koha::Reports->running parses this comment, and external
  log/audit tooling that consumes Koha SQL relied on the previous
  format (/* saved_sql.id: <id> */). Calling out the new format
  explicitly makes the public contract visible to anyone reading the
  POD or grepping for it, and warns future contributors that changing
  the wrapper will break running() too.

- reports/guided_reports.pl gets an inline comment explaining the
  TOCTOU window between the count check and the actual report
  execution. The window is intentional - the guard exists to stop
  accidental double-clicks and two-tab submissions, not to be a
  serializing lock - so worst case is one extra concurrent run, which
  is acceptable and cheaper than the alternative.

No behaviour change.

Test plan:
1) prove t/db_dependent/Koha/Reports.t still passes.
2) perldoc Koha::Report -> prep_report section now mentions the
   saved_sql.id / user_id wrapper format.

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-07 07:56:19 -06:00