Commit Graph

8891 Commits

Author SHA1 Message Date
Olivia Reynolds bb83b600ec
Bug 12757: Set float type on OpenDocument cells
Test plan:
1. Navigate to Reports > Create from SQL.
2. Create a new report with a name and the following SQL query:

SELECT 'test', 1, '2'

3. Run the report.
4. Under the Download dropdown, select "Open Document Spreadsheet".
5. Verify a ".ods" file is downloaded.
6. Open the downloaded spreadsheet.
7. Verify the two number-like columns are handled as such. This depends
   on your choice of spreadsheet software:
   - In Excel, the numbers should not have a leading single quote in the
     edit-bar when selected.
   - In Google Sheets, the numbers should be right-aligned, and
     selecting both of them should display their sum in the bottom
     toolbar.
8. Run `prove t/Koha/Util/OpenDocument.t` and verify all tests were
   successful.

Sponsored-by: Open Fifth
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-06-18 16:02:11 +00:00
Lari Taskula fed20335a4
Bug 28915: Add test for AddModificationTemplateAction
To test:
1. prove t/db_dependent/MarcModificationTemplates.t

Observe test failing with the following error

t/db_dependent/MarcModificationTemplates.t .. 1/135 Control fields (generally, just tags below 010) do not have subfields, use data() at /home/koha/Koha/Koha/SimpleMARC.pm line 490.

Signed-off-by: Anneli Österman <anneli.osterman@koha-suomi.fi>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-06-15 15:24:11 +00:00
Lari Taskula 534c54f730
Bug 28915: Add control field support to Koha::SimpleMARC::update_field()
Before this patch, control fields were not modifiable using this subroutine.

Control fields use character positions instead of subfields. When modifying
control fields, this patch makes the subroutine's parameter "subfield" to indicate
a character position. An example

Koha::SimpleMARC::update_field({
  record => $record,
  field  => '008',
  subfield => '2',
  values => [09],
});

changes field 008 starting from character position 2 to contain values "09".
This replaces char pos 2 with "0", and char pos 3 with "9".

To test:
1. prove t/SimpleMARC.t

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Anneli Österman <anneli.osterman@koha-suomi.fi>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-06-15 15:24:05 +00:00
Martin Renvoize 081dbc1422
Bug 42485: (QA follow-up) Add explicit JSON::PP import and test coverage
Add explicit `use JSON::PP ()` to Elasticsearch.pm and the test file
to make the dependency on JSON::PP::false visible rather than relying
on YAML::XS loading it as a side effect.

Extend the get_elasticsearch_mappings() test subtest to assert that
date_detection and numeric_detection are disabled at the mapping root.

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-06-12 16:24:16 +00:00
Jonathan Druart e5aa1bf86d
Bug 38122: Add tests
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-06-12 16:24:14 +00:00
Owen Leonard 89da78b3b9
Bug 42684: Capitalization: No Barcode
This patch corrects the capitalization of the phrase "No Barcode" and
several other instances of incorrect capitalization.

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Laura_Escamilla <laura.escamilla@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-06-12 16:24:07 +00:00
Pedro Amorim 28c94aeb15
Bug 42783: Fix ManageMarcImport_spec.ts
If import_batch_profiles is slow to respond, it'll trigger select.change() in stage-marc-import.tt and change the format to ISO2709 before the form is submitted, causing the error.

cypress run --spec t/cypress/integration/Tools/ManageMarcImport_spec.ts

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-06-08 14:16:25 +00:00
Eric Phetteplace 9c994035fe
Bug 42723: Purchase suggestion 500 when EmailPurchaseSuggestions is set to BranchEmailAddress
Testing plan:
- Set EmailPurchaseSuggestions to BranchEmailAddress
- Go to create suggestion on the staff side /suggestion/suggestion.pl?op=add_form
- Create a suggestion with Library: Any
- 500 error: inbound_email_address is not a method of undef
- Apply patch & repeat
- Suggestion created

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-06-05 14:26:09 +00:00
Martin Renvoize 3ed47b65e8
Bug 42764: Use inline codespell:ignore for SAN-Ouest Provence in templates
Rather than excluding the entire about.tt files from codespell scanning,
annotate only the specific lines containing the proper noun "Provence"
(SAN-Ouest Provence, a French library co-operative and Koha sponsor) with
an inline TT comment that codespell recognises as a per-line ignore.

This lets codespell continue to check the rest of each file for genuine
spelling mistakes, while still catching accidental "Provence" for
"Province" in any other template not carrying this annotation.

Replaces the file-level exceptions added to Koha::Devel::Files in
favour of the more surgical inline approach.

Test plan:
1. Apply patch
2. Verify "Provence" on the annotated lines produces no codespell output:
   codespell -d --ignore-words .codespell-ignore \
     koha-tmpl/intranet-tmpl/prog/en/modules/about.tt
   => no output
3. Verify the rest of about.tt is still checked by introducing a
   deliberate typo elsewhere in the file and confirming codespell flags it
4. prove xt/author/codespell.t
=> All tests pass

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
2026-06-04 10:59:21 +01:00
Martin Renvoize 04809de849
Bug 42764: Fix spelling errors across the codebase
Correct genuine spelling errors identified by the codespell 2.4.x
full scan after the KTD container OS upgrade. Changes are in
comments, POD, strings, and template text across 55 files.

"SAN Ouest Provence" (the French library co-operative and Koha
sponsor) is preserved as a proper noun. Perl copyright lines
receive an inline # codespell:ignore annotation; about.tt files
(contributor attribution pages) are added to the Koha::Devel::Files
codespell exception list so that future uses of "Provence" as a
typo for "Province" are still caught in all other files.

Notable user-visible fixes:
- "submiting" -> "submitting" in authority and bibliographic merge screens
- "deleteable" -> "deletable" in patron exception messages
- "Acquistions" -> "Acquisitions" in reports dictionary

Test plan:
1. Apply patches
2. In the staff interface, go to Cataloguing > Merge records and
   confirm the submit button reads "Submitting" (not "Submiting")
3. In the staff interface, go to Authorities > Merge and confirm
   the same correction
4. Attempt to delete a patron with outstanding issues and confirm
   the error message reads "deletable" (not "deleteable")
5. prove xt/author/codespell.t
=> All tests pass

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-06-03 16:09:04 +00:00
Pedro Amorim 8c4344cced
Bug 42705: Fix SCO spec WebBasedSelfCheck setup
cy.login() in beforeEach broke the test in two ways: the intranet staff session cookie bled into the OPAC request (HTTP cookies have no port scope in
browsers), and navigating from intranet→OPAC mid-test hit a cross-origin block in Cypress. The afterEach suffered the same race condition - the syspref POST fired before the login redirect completed.

Replace with cy.request(), which makes HTTP calls at the runner level without touching the browser's current origin. cy.visitOpac() is then the first
browser navigation, so no cross-origin issue arises. A three-step flow satisfies Koha's CSRF middleware:
1) GET the login page to obtain a session and its token
2) POST credentials to authenticate
3) POST to the svc endpoint.

This fixes the #barcode and #patronlogin not found issues

The CSRF token also requires encodeURIComponent() — base64 uses +, which a
URL-encoded form body decodes as a space, silently corrupting the token and causing the login to fail.

This resolves the 403 Forbidden issue

Everything must pass:
$ cypress run --spec t/cypress/integration/OPAC/SCO_spec.ts

as well as npm run cypress open (cypress ui)

ktd selenium:
$ perl /kohadevbox/misc4dev/run_tests.pl --run-only t/cypress/integration/OPAC/SCO_spec.ts

squash

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-06-02 15:07:22 +00:00
Pedro Amorim d5ae629d8c
Bug 42705: Add HttpClient_spec.ts
This fails without the fix patch in this set:
cypress run --spec t/cypress/integration/HttpClient_spec.ts

It passes with the fix

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-06-02 15:07:21 +00:00
Pedro Amorim dc59aadc4a
Bug 42733: Add tests
Apply tests patch only, run:
yarn cypress run --spec t/cypress/integration/Tools/ManageMarcImport_spec.ts

Confirm it fails with the same error as Jenkins:
Timed out retrying after 10000ms: `cy.wait()` timed out waiting `10000ms` for the 2nd request to the route: `jobPoll`. No request ever occurred.

Apply fix patch. Run again.

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-06-02 15:07:18 +00:00
Jonathan Druart 147720ca1d
Bug 42606: Add Cypress tests
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-26 08:37:34 -06:00
Jonathan Druart 7cdae514a4
Bug 27826: Turn on WebBasedSelfCheck to fix Cypress tests
On Jenkins, SCO is not setup like it is in ktd after a reset_all
from insert_data.pl
251 sub configure_selfcheckout {

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-26 08:37:26 -06:00
Lucas Gass 4f58ed8953
Bug 27826: (RM follow-up) Attempt to fix failing test
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-22 17:12:22 -06:00
Martin Renvoize 7a7a3ab2c6
Bug 40383: (follow-up) Fix EdifactModal Cypress test reliability
Three fixes to make all 27 EdifactModal Cypress tests reliably pass:

1. insertData.js: fix currency FK constraint violation (use an existing
   currency rather than creating an undefined one).

2. Koha/Edifact/File.pm: add missing use statements for File::Basename
   and File::Temp so the Cypress task can load the module.

3. EdifactModal_spec.ts:
   - Replace arbitrary cy.wait() calls with condition-based assertions
     throughout (expand/collapse animations, Bootstrap modal state).
   - Fix search timing: add cy.intercept + cy.wait("@ediMsg") in the
     Search Functionality beforeEach so initializeSearch is wired before
     input events fire; use invoke("val")+trigger("input") instead of
     type() to bypass the 500ms debounce race.
   - Fix modal close tests: attach a shown.bs.modal listener before
     opening the modal so we can wait for Bootstrap's 300ms show
     animation to complete (_isTransitioning → false) before calling
     hide(). Without this wait, hide() is silently blocked when the Ajax
     response is faster than the animation (common in KTD). Use
     bootstrap.Modal.getInstance().hide() as the programmatic fallback
     since data-bs-dismiss and keyboard events are unreliable in headless
     Cypress/Electron.
   - Fix edifact_interchange.js: remove duplicate &format=json appended
     to URLs that already contain it.

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-22 12:59:11 -06:00
Martin Renvoize 7048a657e7
Bug 40383: (follow-up) Fix failing EdifactModal Cypress tests
Three issues caused the EdifactModal_spec.ts test suite to fail:

1. insertSampleEdifactMessages inserted a vendor with listprice='USD' and
   invoiceprice='USD', but those columns have FK constraints against the
   currency table and USD is not pre-populated in KTD's default install.
   Drop the currency columns from the INSERT so they default to NULL.

2. Koha::Edifact::File::vendor() and basket() called
   Koha::Acquisition::Bookseller and Koha::Acquisition::Basket without
   use-ing them. The edifactmsgs.pl table embeds both on every API call,
   so a missing module caused a 500 and an empty table.

3. showMessage() already appended &format=json before delegating to
   showMessageFromUrl(), which then appended it a second time. Remove the
   redundant copy from showMessage().

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-21 10:49:43 -06:00
Pedro Amorim b5efda989f
Bug 37762: (QA follow-up): Fix insertData.js
cypress run --spec t/cypress/integration/t/insertData.ts

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-21 10:21:40 -06:00
Lucas Gass 1ed156ef40
Bug 42545: (RM follow-up) Tidy test file
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-20 09:04:54 -06:00
Martin Renvoize 0a0dcee152
Bug 42545: (QA follow-up) Add unit tests for holiday subtraction when return time is before due time
Adds a dedicated subtest covering the specific scenario: daily loans have a
due time of 23:59, so a return earlier in the day on a holiday would
previously cause days_between to exit its loop before processing the end
date, silently skipping the holiday subtraction.

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-20 09:04:54 -06:00
Martin Renvoize 6ca7c1118b
Bug 42545: (QA follow-up) Add POD for _init and _holidays and fix incorrect test expectation
The existing 'days: 289 hours, 2 holidays' test asserted 8-1=7 but its own
description named 2 holidays. The expected value matched the buggy behaviour
(loop exiting before the holiday end date) rather than the correct result.
Update to 8-2=6 to reflect the fix.

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-20 09:04:53 -06:00
Kyle M Hall 7dc223b30a
Bug 42547: Fix SIP performance if sip2_resource_last_modified not set in cache
In Koha, the sip2_resource_last_modified key is updated any time the SIP config is edited from the SIP2 editor in the staff interface ( institutions, accounts, system preference overrides ).

If sip2_resource_last_modified is missing from memcached, Koha SIP emits "Couldn't find sip2_resource_last_modified, considering configuration not up to date" in the logs, and fetches the entire configuration from the database, *for each request*.

This causes SIP performance to drop significantly. In my production testing with 83 institutions and 171 accounts the login message response time dropped from 0.283 seconds to 2.899 seconds.

I think the solution is pretty simple. If there is a cache miss on sip2_resource_last_modified, SIP should load the config from database as it does already, but then it should also set sip2_resource_last_modified!

Test Plan:
1) Apply this patch
2) Prove t/db_dependent/Koha/SIP2/SIP2ModuleMigration.t

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-18 09:30:20 -06:00
Jonathan Druart 4da822b6a1
Bug 42578: Prevent Koha/Hold.t to fail on date comparison
We must use t::lib::Dates::compare to compare dates in test.

Test plan:
Confirm that `prove t/db_dependent/Koha/Hold.t` still returns green
after this patch

Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-18 09:30:19 -06:00
Pedro Amorim e931157dc7
Bug 42255: Add tests
prove t/db_dependent/Reserves.t

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-18 09:30:15 -06:00
Lucas Gass 11d7450e2a
Bug 37762: (RM follow-up): Tidy t/db_dependent/api/v1/iso18626/request.t
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-15 08:11:13 -06:00
Pedro Amorim 4b525d9e3e
Bug 37762: (QA follow-up): Warn and return 500 on schema validation failure in progress_request
An exception is not implemented as progress_request is called in
different circulation contexts (hold is placed, checkout happens,
etc) and those actions should not be dependent on the outcome of
progress_request, i.e. if progress_request fails due to schema
validation failure, the circulation action should happen as before.

prove t/db_dependent/Koha/ILL/ISO18626/Request.t
prove t/db_dependent/api/v1/iso18626/request.t
cypress run --spec t/cypress/integration/ILL/SupplyingRequests.ts

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-15 08:11:12 -06:00
Pedro Amorim 4cf61f6c73
Bug 37762: (QA follow-up): Fix cypress ILL tests
cypress run --spec t/cypress/integration/ILL/*

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-15 08:11:10 -06:00
Brendan Lawlor 9f8cb217c0
Bug 32773: (follow-up) Unit tests
Signed-off-by: Miranda Nero <mnero@oslri.net>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 16:05:37 -06:00
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 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 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 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 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
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
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 c8f0f064d6
Bug 41918: (QA follow-up) Add unit tests for Koha::Reports->running
Adds a 'running' subtest covering the new method:

- Returns a Koha::Reports resultset (object identity, not opaque ids).
- Returns an empty resultset when nothing is in flight, and when the
  user_id / report_id filter does not match any process.
- Parses saved_sql.id markers out of synthetic processlist rows and
  resolves them to real Koha::Report objects, ignoring rows without
  the marker.
- Sends parameterised LIKE binds for user_id (proves the WHERE clause
  is built without string interpolation).
- Falls back to an empty resultset and does not propagate the
  exception when the underlying selectall_arrayref call dies, eg.
  when the database user lacks PROCESS privilege.

To make the failure path mockable without trying to mock DBI::db
(which is not loadable as a separate file), the dbh selectall is
extracted into a tiny Koha::Reports::_processlist_rows helper so
Test::MockModule can replace it cleanly. The helper is otherwise
behaviour-preserving.

Test plan:
1) prove t/db_dependent/Koha/Reports.t -> 11 tests, all pass.
2) Existing prep_report subtest still passes.

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-07 07:56:18 -06:00
Martin Renvoize 521ddaacad
Bug 41918: (QA follow-up) Update prep_report tests for new SQL comment
The first patch in this series changed the SQL comment appended by
Koha::Report::prep_report from

    /* saved_sql.id: <id> */

to

    /* { saved_sql.id: <id> } { user_id: <user_id> } */

but did not update the existing assertions in t/db_dependent/Koha/Reports.t,
leaving three subtest failures in the prep_report subtest. Refresh the
expected strings to match the new format and pick up the userenv-derived
user_id (or 0 when no userenv is in scope, matching prep_report's fallback).

Test plan:
1) Apply this follow-up.
2) prove t/db_dependent/Koha/Reports.t
3) Verify all 10 tests pass (previously 3 subtests of prep_report failed).

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-07 07:56:17 -06:00
Matt Blenkinsop 25a2e938fa
Bug 26355: (follow-up) Fix cypress tests
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-07 07:56:15 -06:00
Jonathan Druart 084c07a0fe
Bug 27826: Fix OPAC/SCO_spec.ts
1. The DELETE in afterEach was not needed
2. The test was failing randomly on the UPDATE of the beforeEach
  `Duplicate entry '+42+' for key 'itembarcodeidx'`
I don't explain it, but this patch should fix the failure.

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-07 07:56:14 -06:00
Pedro Amorim 5d716d1e28
Bug 41956: Remove visual_hold_group_id
Signed-off-by: Bob Bennhoff <bbennhoff@clicweb.org>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-06 15:21:00 -06:00
Pedro Amorim 2ed777a854
Bug 41983: (QA follow-up): Rebuild the holds queue when groups are edited
Test plan (ktd)
0) Update the database (ktd, ignore if sandbox):
  $ updatedatabase
1) Enable 'RealTimeHoldsQueue' and 'DisplayAddHoldGroups' system preferences
2) restart_all # This is required or the worker won't pick up the new sys pref values
3) Place at least 2 holds for a patron on different items/biblios, without grouping them:
  <staff_url>/cgi-bin/koha/members/moremember.pl?borrowernumber=19
4) Build the holds queue once to get a baseline:
  $ perl misc/cronjobs/holds/build_holds_queue.pl --force
5) Visit the holds queue and confirm the holds appear without a group indicator:
  <staff_url>/cgi-bin/koha/circ/view_holdsqueue.pl?branchlimit=&itemtypeslimit=&run_report=1
6) Create a hold group for those holds via the patron page
 <staff_url>/cgi-bin/koha/circ/circulation.pl?borrowernumber=<patron_borrowernumber>
7) Without running build_holds_queue.pl, refresh the holds queue, confirm the 'part of a hold group' indicator now appears
8) Ungroup the holds, refresh the holds queue, confirm the 'part of a hold group' is no longer showing
9) Run the unit tests:
  $ prove t/db_dependent/Reserves/HoldGroup.t

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-06 15:20:58 -06:00
Lucas Gass 04a3371ee9
Bug 42103: (follow-up) Fix failing test
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-06 09:52:19 -06:00
Matt Blenkinsop c23b2fb2f7
Bug 26355: (follow-up) Add a fallback value for patronValues in insertSamplePatron
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-06 09:52:18 -06:00
Martin Renvoize dfb875154d
Bug 42188: (follow-up) Update ModBiblio test for new info format
The 'ModBiblio on invalid record' subtest asserted the action log info
column contained 'biblionumber', but Koha::Biblio::_unblessed_for_log
restricts the logged hash to frameworkcode, opac_suppressed, and serial.
The biblionumber lives in action_logs.object, not in the info JSON.

Update the regex to match the new "biblio { ... }" prefix format set by
C4::Log::logaction so the assertion confirms biblio data is logged
without depending on a field that is intentionally excluded.

Test plan:
1. prove t/db_dependent/Biblio.t

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-06 09:52:11 -06:00
Martin Renvoize e7eb27d48e
Bug 29016: (QA follow-up) Expand action_logs API and test coverage
Build on the new ActionLog DBIC relations to expose them as opt-in
embeds, and shore up gaps in the test coverage that QA flagged.

Swagger
  * paths/action_logs.yaml declares an x-koha-embed header parameter
    constrained to the supported relations (librarian, patron).
  * definitions/action_log.yaml adds the corresponding optional
    `librarian` and `patron` object fields.

Tests
  * Convert the single 24-test subtest into focused subtests:
    - authorization (403 vs 200)
    - simple typed filters
    - q-DSL: multi-value module, info LIKE, combined filter
    - embeds: librarian and patron, with and without x-koha-embed
    - pagination + X-Total-Count and order_by
  * Mock AuthSuccessLog/AuthFailureLog/BorrowersLog to 0 to remove the
    flakiness where the API GET itself appended an AUTH log row between
    delete and assertion.
  * Build the test librarian with both `tools` and `borrowers` flags so
    embedded patron fields are not redacted by Koha::Patron->is_accessible.
  * Use a small build_fixtures() helper to avoid copy-pasting setup
    across subtests.

Test plan:
  1. yarn build && restart_all  (refresh swagger bundle)
  2. prove t/db_dependent/api/v1/action_logs.t  (all subtests green)
  3. curl -H 'x-koha-embed: librarian,patron' \
       /api/v1/action_logs?module=MEMBERS  -- patron and librarian
       objects appear in the response.

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-05 13:42:09 -06:00
Kyle M Hall 4edc85cf29
Bug 29016: Add unit tests
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-05 13:42:07 -06:00
Martin Renvoize 4cead7f389
Bug 42032: (follow-up) Eliminate phantom indicator diffs on authority MODIFY
Authority MODIFY action log diffs were emitting bogus entries for every
field with a default ' ' indicator on every save, producing output like:

    _marc.fields.1.040.ind1   ' '   ' '
    _marc.fields.1.040.ind2   ' '   ' '
    _marc.fields.2.150.ind1   ' '   ' '
    _marc.fields.3.667.ind1   ' '   ' '
    ...

even when only a single subfield was edited.

Root cause: Struct::Diff treats a utf8-flagged ' ' as different from a
non-utf8 ' ' SV, even though Perl's eq returns true. ModAuthority was
sourcing the two sides of the diff from different parse paths:

  - $oldrecord = GetAuthority($authid)
      -> MARC::Record->new_from_xml(...) -> indicators arrive utf8-flagged
  - $record (the "after" side) was the in-memory MARC built by the
      editor from CGI parameters -> indicators are bare byte strings

The XML round-trip through AddAuthority normalises the stored copy, but
the in-memory $record we passed to logaction had not been re-parsed, so
every default indicator looked like a change to Struct::Diff.

Fix: after AddAuthority commits the new state, re-read it via
$new_authority->record and pass that to _authority_log_data. Both sides
of the diff now traverse the same new_from_xml path, utf8 flags match,
and Struct::Diff falls silent on unchanged indicators.

This is the symmetric counterpart of how biblios already work in
C4::Biblio: ModBiblio sources both $original_marc and $updated_marc_log
through Koha::Biblio::Metadata::record_strip_nonxml (which also calls
new_from_xml), so biblios don't hit this.

The deeper asymmetry between in-memory editor MARC and stored MARC
(default indicators only get normalised on the XML round-trip) is left
for a separate bug; this patch keeps the action log diff clean without
touching the storage path.

Test plan:
1. prove t/db_dependent/AuthoritiesMarc.t
2. Enable AuthoritiesLog. Edit any authority via the staff UI making a
   single subfield change. Open Tools -> Log viewer for that authority
   and verify the diff column lists only the changed subfield (plus the
   005 timestamp), with no rows for ind1/ind2 of untouched fields.
3. Re-run the same edit a second time changing nothing else; the diff
   should again be limited to 005 + the touched subfield.

Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-05 13:42:06 -06:00
Martin Renvoize 55e2810aac
Bug 42032: (follow-up) Write state JSON to AUTHORITIES info column
Mirrors bug 42188's biblio info-column convention. Generalise the
CATALOGUING-only info-column rewrite branch in C4::Log::logaction to
cover AUTHORITIES as well, using a module-aware prefix map so each
module gets its own prefix ("biblio" / "authority"). For AUTHORITIES
this means MODIFY now stores "authority {pre-change JSON}" and DELETE
stores "authority {final-state JSON}", while ADD stays bare
"authority" (the call site passes the string directly and ADD is
guarded anyway). The biblio behaviour is preserved bit-for-bit.

Test plan:
1. prove t/db_dependent/AuthoritiesMarc.t
2. Enable AuthoritiesLog. Create / modify / delete an authority via
   the staff UI, then check action_logs:
   - ADD    row's info column reads just "authority"
   - MODIFY row's info column reads "authority { ... pre-change JSON ... }"
   - DELETE row's info column reads "authority { ... final-state JSON ... }"
3. prove t/db_dependent/Koha/Biblio.t
4. prove t/db_dependent/Log.t

Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-05 13:42:05 -06:00