Commit Graph

62264 Commits

Author SHA1 Message Date
Jonathan Druart e1072702f8
Bug 41896: Remove C4::Context from Koha::Cache
Signed-off-by: Julian Maurice <julian.maurice@biblibre.com>

Amended-by: Jonathan Druart
Restore ||= op
-    $self->{namespace} = Koha::Config->get_instance->get('memcached_namespace') || 'koha';
+    $self->{namespace} ||= Koha::Config->get_instance->get('memcached_namespace') || 'koha';

Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:27 +00:00
Andrew Fuerste Henry d154cda830
Bug 35797: (QA follow-up) Use https in API comment
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:26 +00:00
Shi Yao Wang b590f1a0a3
Bug 35797: Syspref, schema path file and tests changes
1- Corrected tests according to the comments
2- Removed unused import
3- Added syspref check of 'patronimages'
4- Tweaked swagger path schema

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:25 +00:00
Shi Yao Wang ad190dcc5d
Bug 35797: REST API Add GET route for patronimage and tests
Api changes adding GET route for patronimage

Test plan:
1- Apply the patch
2- Run `npm run api:bundle`
2- Go to administration -> sys.pref. -> set patronimages to allow
3- Log in koha using a user with "list_borrowers" or "edit_borrowers" privileges
4- Have a patron with a profile image (add an image if necessary by
searching for a patron and then clicking on the default profile image on
the top left)
5- Open a an API testing tool (such as postman), write
{intranet_url}/api/v1/patrons/{borrowernumber}/default_image
where {intranet_url} is the base intranet url of koha and {borrowernumber}
is the borrowernumber of a borrower that has an image
6- Add OAuth 2.0 credentials coming from koha (patron -> more -> manage
api keys) and generate a token
7- Send the request and notice the image of the patron is returned
8- Do step 5-7 with a borrowernumber of a patron without an image and a
borrowernumber of a patron that doesn't exist (and other edge cases
where there should be an error message displayed such as "Access
forbidden", "Authentication required", etc.)
9- Notice an appropriate error message is displayed

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: David Nind <david@davidnind.com>

Bug 35797: Rename test file from 'image.t' to 'patron_images.t'

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:24 +00:00
Martin Renvoize 3450f46d8b
Bug 40736: (QA follow-up) Avoid redundant CGISESSID cookie lookups
The cookie is already fetched once into $current_session_cookie
earlier in login(); reuse it instead of calling
$c->req->cookie('CGISESSID') again at each check site.

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:23 +00:00
Lari Taskula b094346030
Bug 40736: Add test
To test:
1. prove t/db_dependent/api/v1/idp.t

Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:22 +00:00
Lari Taskula 1f86fb5616
Bug 40736: Restore commented out tests
Commented out by https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=143438

(or 9c5f6e8c17 (diff-9e449131ec9eb973ff6a851c0fda9a426255591e3f579c79b047fb2763f33e80R275) )

To test:
1. prove t/db_dependent/api/v1/idp.t

Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:21 +00:00
David Cook 20bde64702
Bug 40736: Gracefully handle missing CGISESSID cookie
This change makes the REST API gracefully handle
a missing CGISESSID when trying to do an OAuth/OIDC login
by direct linking.

Test plan:
0. Apply the patch and koha-plack --restart kohadev
1. Set up an OpenID Connect client using the wiki
https://wiki.koha-community.org/wiki/Testing_SSO
2. In an incognito/private window, try directly logging in
with the following URL:
http://localhost:8080/api/v1/public/oauth/login/test/opac
3. Note that you're redirected to opac-user.pl with an auth error
message of "No user session found"
4. Close the incognito/private window
5. In an incognito/private window, try directly logging in
with the following URL:
http://localhost:8081/api/v1/oauth/login/test/staff
6. Note that you're redirected to mainpage.pl with an auth error
message of "No user session found"

Signed-off-by: Lari Taskula <lari.taskula@hypernova.fi>
Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:20 +00:00
Hammat Wele 6490728051
Bug 33758: Add a parameter to use the intranet_catalog_biblio_enhancements_toolbar_button Plugin hook
This patch adds a parameter to call the method intranet_catalog_biblio_enhancements_toolbar_button with a biblionumber in the page catalogue/detail.pl.

Modification of cat-toolbar.inc to display new buttons correctly.

To test :
1. Apply the patch
2. Take a plugin who implements the method intranet_catalog_biblio_enhancements_toolbar_button
3. Check if the parameter biblionumber is passed correctly at this method
4. Create the new button in HTML in the plugin method
(button must be like the ones that are in the toolbar of the page detail.pl)
5. Go to the page in browser and check if the new button is displayed

Signed-off-by: Roman Dolny <roman.dolny@jezuici.pl>

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:19 +00:00
Martin Renvoize 1e0442b847
Bug 41105: (QA follow-up) DRY out gender label rendering
The gender-code-to-label mapping (F/M/O -> Female/Male/Other) was
duplicated between the results table cell and the edit-form select
options in modborrowers.tt. Extract it into a shared
patron-sex-label.inc so there is a single place defining the mapping,
and drop the now-unused "lib" values from the sex options in
tools/modborrowers.pl (labels are supplied by the include, keyed on
the option value, rather than by Perl).

Test plan:
1. Navigate to Patrons and click Search, to display a list of patrons.
2. Select all results and click "Batch patron modification".
3. Verify the "Gender" column displays Female/Male/Other correctly.
4. Verify the "Gender" edit dropdown still offers Female/Male/Other
   and saves correctly.

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:18 +00:00
Martin Renvoize b51a3f111a
Bug 41105: (QA follow-up) Fix gender label translation
The batch patron modification "Gender" column and edit dropdown
hardcoded "Female"/"Male"/"Other" as data passed from
tools/modborrowers.pl, and the "Other" gender label was displayed as
plain text.

Values coming from Perl as template data are never picked up by the
PO extractor, so the gender select options in the edit form could
never be translated. Elsewhere in Koha (moremember.tt,
moremember-brief.tt, memberentrygen.tt, opac-memberentry.tt) the
"Other" gender label is wrapped with tp('gender', 'Other') to give
translators context, since "Other" is ambiguous out of context.

This makes the "Gender" dropdown options translatable directly from
the template, and aligns "Other" with the existing tp('gender', ...)
convention used everywhere else gender is displayed.

Test plan:
1. Navigate to Patrons and click Search, to display a list of patrons.
2. Select all results and click "Batch patron modification".
3. Verify the "Gender" column and "Gender" edit dropdown still work as
   expected.
4. Confirm (e.g. via the .pot file or misc/translator/translate) that
   "Female", "Male" and the "Other" (gender) msgctxt string are now
   extracted for translation from this template.

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:17 +00:00
Olivia Reynolds 0bb26abd5a
Bug 41105: Add gender to batch patron modification
This patch adds the ability to batch-edit the gender field for patrons.

Test plan:
1.  Ensure there are a number of patrons in the database.
2.  Apply patch.
3.  Navigate to Patrons and click Search, to display a list of patrons.
4.  Select all results and click "Batch patron modification".
5.  Verify the "Gender" column is displayed.
6.  Verify the "Gender" column may be toggled under the "Columns"
    dropdown.
7.  Select a subset of the patrons for modification.
8.  Verify there is a "Gender" option beneath the table.
9.  Select "Female" as the gender, and click "Save".
10. Verify the gender of all selected patrons was set to "Female".
11. Repeat with "Male" and "Other" as the gender.
12. Repeat with clearing the gender field by ticking the checkbox next
    to the dropdown and saving. Verify the gender field is blank for
    each selected patron.

Sponsored-by: Open Fifth
Signed-off-by: Laura_Escamilla <laura.escamilla@bywatersolutions.com>
Signed-off-by: Amit Gupta <amit.gupta@informaticsglobal.ai>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:15 +00:00
Pedro Amorim 662020e21b
Bug 42714: RM follow-up: Fix tests
prove t/00-load.t
prove xt/author/pod_coverage.t

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-13 11:28:40 +00:00
Owen Leonard 55bc6f01e0
Bug 41842: (follow-up) Ensure that tidy doesn't trim wanted whitespace
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 16:08:01 +00:00
Owen Leonard 1b00485b27
Bug 41842: (follow-up) Make sure this space doesn't get tidied
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 16:07:59 +00:00
Martin Renvoize 3cd648d52f
Bug 41842: Use space-dash-space separator between course name and section
The staff interface templates were using a bare hyphen with no spaces
when displaying course name and section together, while the OPAC templates
(Bug 42654) use ' - ' (space-dash-space). This brings the staff interface
into alignment with the OPAC convention for consistency and readability.

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 16:07:58 +00:00
Owen Leonard 303ba57409
Bug 41842: Improve translation of course reserves headings
This patch adds some use of I18N functions to course reserves templates
in order to improve the process of translation by adding context and
placeholders. The patch also rewords some headings for clarity and
consistency.

To test, apply the patch and go to course reserves.

- Add a course if necessary.
- Click the course to view it.
- On the course details page, confirm that the page title, breadcrumbs,
  and heading look correct.
- Click "Edit" in the toolbar.
- Check the page title, breadcrumbs, and heading again.
- Return to the course details and click "Add reserves" and check that
  page.
- Submit a barcode or biblionumber and check that page.
- Test the "Batch add reserves" page.

To test the improved I18N, apply the patch and test that the correct
strings are translatable. In this example I'm testing fr-FR:

- Update a translation:

    > gulp po:update
    > cd misc/translator
    > perl translate update fr-FR

- Open the corresponding .po file for the modified strings, e.g.
  fr-FR-messages.po.
- Locate strings pulled from course reserves templates for
  translation, e.g.:

    #: koha-tmpl/intranet-tmpl/prog/en/modules/course_reserves/course.tt:10
    #: koha-tmpl/intranet-tmpl/prog/en/modules/course_reserves/course.tt:42
    #: koha-tmpl/intranet-tmpl/prog/en/modules/course_reserves/course.tt:56
    #, fuzzy, perl-brace-format
    msgid "Edit course {course_name}"
    msgstr "Modifier {course_name}"

- Remove the "fuzzy,"
- Edit the "msgstr" string however you want (it's just for testing)
- Install the updated translation:

  > perl translate install fr-FR

Switch to the translation you updated. Walk through the process of
editing a course and adding course reserves to confirm that your translated strings show up.

Sponsored-by: Athens County Public Libraries
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 16:07:55 +00:00
Pedro Amorim 4960d6987d
Bug 42973: (RM follow-up) Update tests number
Because of bug 42866
prove t/db_dependent/Koha/AdditionalContents.t

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 15:49:52 +00:00
Laura_Escamilla 89f6fcc4cd
Bug 42973: Unit test
Added a unit test to confirm that search_for_display orders manually positioned news first, followed by unnumbered news by publication date descending.

Test passes:

prove t/db_dependent/Koha/AdditionalContents.t

Signed-off-by: Gretchen Maxeiner <MaxeinerGL@gcc.edu>
Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 15:49:51 +00:00
Laura_Escamilla 70caff963a
Bug 42973: Restore manual ordering for news
To test:
1. Create four OPAC news items:

   - "Pinned news item" with "Appear in position" = 1 and an older publication date.

   - "Newest unnumbered news item" with no position and the newest publication date.

   - "Middle unnumbered news item" with no position and an intermediate publication date.

   - "Oldest unnumbered news item" with no position and the oldest publication date.

2. View the OPAC main page.

3. Confirm the news items are ordered by publication date, with the newest item first.

Apply the patch.

4. Reload the OPAC main page.

5. Confirm the manually positioned news item appears first.

6. Confirm the remaining news items are ordered by publication date descending.

7. Confirm news items without an "Appear in position" value continue to display newest first.

8. Sign off and have a wonderful day!

Signed-off-by: Gretchen Maxeiner <MaxeinerGL@gcc.edu>
Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 15:49:51 +00:00
Katrin Fischer bb53e653f3
Bug 43239: (QA follow-up) Rephrase hint on subscription form
This is to clarify that the item's current item type will
not be changed, no matter what settings have been used in
the subscription.

Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 15:49:50 +00:00
David Nind 5005019b5d
Bug 43239: (follow-up) Update wording for hint
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 15:49:50 +00:00
Emmi Takkinen 02515ebcc7
Bug 43239: Preserve item item type if previousitemtype column is undefined
It is possible to create serial item with wrong itemtype if syspreference
makePreviousSerialAvailable is enabled and field "item type for older issues"
isn't filled when creating a subscription for biblio record. This happens
when multiple items are created. In installations where itemtypes differ
between items and biblios, this causes data inconsistencies and leads to
errors in biblios Holdings table.

This patch changes behaviour of serials-edit.pl so that if
makePreviousSerialAvailable is enabled and subscriptions previousitemtype
column is NULL, previous serial items itype column is preserved. It also
adds a hint text to subscription form about this change.

To test:
1. Enable systempreference makePreviousSerialAvailable.
2. Create new biblio record.
3. Create a new subscription for biblio record you made, select option
"Create an item record", select different item type from "Item type"
selection than biblio record has but leave selection "item type for older
issues" empty.
4. Receive a serial item for subscription. Check from biblio records
Holdings table that its item type matches item type selected in step 3.
5. Now receive 3 serial items. After creating them check Holdings table again.
=> Note that first item created now has same item type as biblio record.
6. Apply this patch, restart services.
7. Create new subscription, fill needed fields as in step 3.
=> Note that there is a new hint text after field "item type for older issues".
8. Repeat steps 4. and 5.
=> Note that now all items have same item type.

Sponsored-by: Koha-Suomi Oy
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 15:49:49 +00:00
Pedro Amorim a0ac15d8b3
Bug 35104: DBRev 26.06.00.013
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 15:49:49 +00:00
Martin Renvoize 1b4373eea3
Bug 35104: Update Exporter/Record.t fixture for the new store() validation
This test built a "bad" biblio by storing invalid MARCXML directly via
Koha::Biblio::Metadata->store(), which now rejects it. Simulate
legacy corrupt data already in the database by writing it straight to
the DBIC row, bypassing the new validation, instead.

Signed-off-by: Baptiste Bayche <baptiste.bayche@inlibro.com>
Signed-off-by: Baptiste Wojtkowski <baptiste.wojtkowski@biblibre.com>
Sponsored-by: OpenFifth
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 15:45:06 +00:00
Martin Renvoize 6726b1a254
Bug 35104: Catch invalid metadata and surface repair warnings in AddBiblio/ModBiblio
AddBiblio/ModBiblio/ModBiblioMarc gain an optional warnings arrayref
option: any repair messages recorded by Koha::Biblio::Metadata->store()
(see previous commit) are appended to it via object_messages, so a
caller can show the cataloguer what was automatically fixed instead of
the fix happening invisibly.

AddBiblio also now distinguishes Koha::Exceptions::Metadata::Invalid
from other errors in its catch block and rethrows it, so a caller can
tell "this record is unrecoverable" apart from an unexpected internal
error and react accordingly (see following bugs for callers doing so).

The inline StripNonXmlChars calls in TransformHtmlToMarc are removed,
since stripping is now handled centrally and consistently by
Koha::Biblio::Metadata->store() rather than ad-hoc at every call site.

Signed-off-by: Baptiste Bayche <baptiste.bayche@inlibro.com>
Signed-off-by: Baptiste Wojtkowski <baptiste.wojtkowski@biblibre.com>
Sponsored-by: OpenFifth
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 15:45:05 +00:00
Martin Renvoize 112712e31c
Bug 35104: Recover MARCXML that fails to decode, or throw when unrecoverable
Koha::Biblio::Metadata->store() now validates that MARCXML round-trips
through MARC::Record before saving it, rather than saving whatever was
given and letting corruption surface later as an opaque failure
somewhere downstream.

Two faults are recovered automatically, and either or both may apply
to the same record:

- non-XML characters (recorded as nonxml_stripped, recovered via
  StripNonXmlChars)
- datafields with no subfields at all, which MARC::File::XML refuses
  to parse (recorded as empty_datafield_stripped, recovered by
  removing the empty datafield)

Each recovered fault is logged, reported via object_messages for the
caller to act on, and recorded as a biblio_metadata_errors row (tag
and subfield included where identifiable) for later review - except
where an identical row already exists for the same metadata_id, so a
source record that stays dirty across repeated saves (e.g. re-harvested
from an external repository) doesn't pile up duplicate rows for the
same fault. Existing rows are otherwise left alone on a clean save,
since they're review flags requiring explicit resolution, not a cache
to invalidate.

If the MARCXML cannot be recovered at all, Koha::Exceptions::Metadata::Invalid
is thrown. The recovery logic is exposed as a repair_marcxml class
method so other callers that parse MARCXML ahead of a store() (see
following bugs) can reuse it instead of re-implementing it.

Signed-off-by: Baptiste Bayche <baptiste.bayche@inlibro.com>
Signed-off-by: Baptiste Wojtkowski <baptiste.wojtkowski@biblibre.com>
Sponsored-by: OpenFifth
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 15:45:04 +00:00
Martin Renvoize b80a26eb51
Bug 35104: Add Koha::Biblio::Metadata::Error(s) object classes
Thin Koha::Object(s) wrappers around biblio_metadata_errors. error_type
is restricted to a known set of constants, validated on store(), so a
typo'd or unknown value fails loudly rather than writing an
unrecognised value into the database. Errors::by_type() gives callers
a named filter instead of hand-rolling the same search().

Signed-off-by: Baptiste Bayche <baptiste.bayche@inlibro.com>
Signed-off-by: Baptiste Wojtkowski <baptiste.wojtkowski@biblibre.com>
Sponsored-by: OpenFifth
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 15:45:02 +00:00
Martin Renvoize 50b0ba401b
Bug 35104: Guard Koha::Exceptions::Metadata::Invalid::full_message against undef fields
full_message() interpolated id/biblionumber/format/schema/decoding_error
directly into a sprintf without checking definedness, producing Perl
warnings whenever one of them is unset (e.g. a new, not-yet-stored
metadata object with no id yet).

Signed-off-by: Baptiste Bayche <baptiste.bayche@inlibro.com>
Signed-off-by: Baptiste Wojtkowski <baptiste.wojtkowski@biblibre.com>
Sponsored-by: OpenFifth
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 15:45:01 +00:00
Martin Renvoize 0490204f7b
Bug 35104: Add koha_object_class to BiblioMetadataError schema result
Signed-off-by: Baptiste Bayche <baptiste.bayche@inlibro.com>
Signed-off-by: Baptiste Wojtkowski <baptiste.wojtkowski@biblibre.com>
Sponsored-by: OpenFifth
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 15:45:00 +00:00
Martin Renvoize 7d9562c1b6
Bug 35104: Automated Schema Update
Signed-off-by: Baptiste Bayche <baptiste.bayche@inlibro.com>
Signed-off-by: Baptiste Wojtkowski <baptiste.wojtkowski@biblibre.com>
Sponsored-by: OpenFifth
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 15:44:59 +00:00
Martin Renvoize 22b4acf8d2
Bug 35104: Add biblio_metadata_errors table for per-fault error tracking
Adds biblio_metadata_errors to record individual faults (non-XML
characters, empty datafields, ...) found and recovered when saving a
bibliographic record's MARCXML, so they can be surfaced to
cataloguers and explicitly resolved once reviewed.

Signed-off-by: Baptiste Bayche <baptiste.bayche@inlibro.com>
Signed-off-by: Baptiste Wojtkowski <baptiste.wojtkowski@biblibre.com>
Sponsored-by: OpenFifth
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 15:44:58 +00:00
Laura_Escamilla 1ffbc32ad2
Bug 43019: Prevent access to pages belonging to another library (staff side)
To test:
1. Create two patron accounts:
    * One patron whose home library matches the library assigned to the page.
    * One patron whose home library is different from the library assigned to the page.
2. Create a new page with the following settings:
    * Display location = OPAC
    * Library = a specific library
    * Publication date = Today
    * Title and Content = minimally necessary content
3. Save the page.
4. Right-click the OPAC link and copy the link address.
5. Open the link in an incognito or private browser window without signing in.
    * Confirm that the library-specific page is not displayed.
    * Confirm that a 404 page is shown.
6. In the incognito window, sign in using the patron account whose home library matches the page library.
7. Open the copied OPAC link again.
    * Confirm that the page is displayed.
8. Sign out and sign in using the patron account whose home library does not match the page library.
9. Open the copied OPAC link again.
    * Confirm that the page is not displayed.
    * Confirm that a 404 page is shown.
10. Edit the page and change Library to All libraries.
11. Open the OPAC link in an incognito or private browser window without signing in.
    * Confirm that the page is displayed.
12. While signed in as each patron account, open the OPAC link again.
    * Confirm that the page is displayed for patrons from both libraries.
13. Create or edit a page with the following settings:
    * Display location = Staff interface
    * Library = a specific library
    * Publication date = Today
    * Title and Content = minimally necessary content
14. Sign in to the staff interface using a staff account whose library matches the page library.
15. Open the page from the staff interface.
    * Confirm that the page is displayed.
16. Sign out and sign in using a staff account whose library does not match the page library.
17. Open the staff page link directly.
    * Confirm that the page is not displayed.
    * Confirm that a 404 page is shown.
18. Edit the staff page and change Library to All libraries.
19. Open the page while signed in with staff accounts from both libraries.
    * Confirm that the page is displayed for both accounts.
20. Repeat the OPAC and staff interface checks using Display location = Staff interface and OPAC.
    * Confirm that the page is displayed in both interfaces for users from the matching library.
    * Confirm that users from a different library receive a 404 page.
    * Confirm that pages assigned to All libraries are available in both interfaces.

Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:48 +00:00
David Cook e50267072f
Bug 43019: Fix branch comparison
This change fixes the branch comparison between the Page
and the user. Previously, it was doing a numeric "!=" and now it
does the string comparison "ne". Also, if no environmental variable
is set for the default branch, it defaults to an empty string
for anonymous (ie non-authenticated) users.

Test plan:
0. Apply the patch
1. restart_all
2. Log into the staff interface
3. Go to Tools
4. Click on "Pages"
5. Create a Page for All Libraries for the OPAC
6. Copy the "OPAC" link in the "Page URL" table cell and open it
in a private window or a separate browser
7. Note that the page appears
8. Now change the "Page" to a specific library
9. Revisit the URL in the private window
10. Note that it now gives a 404 error
11. Log into the OPAC with a user whose library matches the libary
of the Page
12. Note that now you can view the URL again
13. Change the library of the user or the Page
14. Note that you cannot see the Page now

Signed-off-by: Phil Ringnalda <phil@chetcolibrary.org>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:47 +00:00
Jonathan Druart a45638d8fc
Bug 42866: Prevent SQL injection in Koha::AddtionalContents->search_for_display
Signed-off-by: Sanjar Tulkinov Anvar o'g'li <sanjarbiy11@gmail.com>

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:46 +00:00
Martin Renvoize f3f6f15938
Bug 42847: (QA follow-up) Clear session state on all login_core exit paths
login_core only cleared leftover session state on the failed-auth
branch. The earlier 'SIP access not authorized' return (unknown
terminal id) left any account/ils/institution/policy/credentials from
a prior connection on a reused prefork worker in place.

Move the reset to the top of login_core so every non-success exit path
leaves clean state, and only a successful api_auth re-establishes the
session. This keeps the no-authenticated-state-until-auth invariant in
a single place rather than duplicating the key list per branch.

Also extend the unit test to cover the unknown-terminal path on a
reused worker.

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:45 +00:00
Kyle M Hall 50a4389813
Bug 42847: Prevent previously authenticated user
After a SIP terminal logs in successfully, a later connection handled by the
same worker could bypass authentication entirely. login_core() stores the account
in the session before calling api_auth(), and left it in place when authentication
failed. The check in raw_transport() that is meant to drop unauthenticated connections
only looks at $self->{account}->{id}, which is now populated straight from the SIP config,
so the connection is treated as logged in.

Test Plan:
1) Create a SIP user with the username and password "term1"
2) Restart the SIP server
3) Apply the first patch
4) prove t/db_dependent/SIP/MsgType.t
5) Note the new test fails
6) Telnet to the SIP server port ( 6001 for ktd )
5) Send a successful login: 9300CNterm1|COterm1
6) Note you get a 941 back
7) Disconnect, then telnet to localhost 6001 again
8) Send a bad login: 9300CNterm1|COterm2
9) Note you get a 940 back, but the connection stays open
10) Send a patron information request, using a real patron cardnumber:
    6300120260615    110310          AOCPL|AA23529001000463
11) Note you get a 64 patron information response with the patron's data back,
    even though the login failed!
12) Apply the second patch
13) prove t/db_dependent/SIP/MsgType.t
14) Note the subtest now passes!
15) Restart all the things!
16) Repeat steps 4 to 10
17) Note the the patron info request returns no patron data and the connection is dropped!

Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:43 +00:00
Kyle M Hall d56dc2bfa8
Bug 42847: Add unit tests
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:42 +00:00
Jonathan Druart 887b163652
Bug 42749: Prevent SQL injection from GetInvoices (order_by)
Signed-off-by: Sanjar Tulkinov Anvar o'g'li <sanjarbiy11@gmail.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:41 +00:00
Martin Renvoize 5aa86845f5
Bug 42747: (QA follow-up) Parameterize query, dedupe, and log rejections
The original fix only whitelisted image_name at the point it's saved
in edit-layout.pl, leaving the actual injection sink in create-pdf.pl
unparameterized. This adds defense-in-depth by fixing the query itself,
avoids a redundant duplicate call to get_all_image_names() (already
fetched earlier in the script as $image_names), and logs rejected
image_name values instead of silently discarding them so tampering
attempts leave an audit trail.

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:40 +00:00
Jonathan Druart bbbaa83c1c
Bug 42747: Prevent SQL injection via image_name in edit-layout
Signed-off-by: Sanjar Tulkinov Anvar o'g'li <sanjarbiy11@gmail.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:39 +00:00
Martin Renvoize b0c86b0fcf
Bug 42746: (QA follow-up) Sanitize agefield and substitution field at the sink too
The original fix only whitelisted agefield, condition_field, and
substitution_field at the point they're saved in
tools/automatic_item_modification_by_age.pl, leaving the actual
consumer of the stored syspref, C4::Items::ToggleNewStatus, trusting
agefield and substitution field unchecked. agefield is spliced
directly into raw SQL (TO_DAYS($agefield)) and so can't be
parameterized like an ordinary value; substitution field reaches a
dynamic method call ($item->$field($value)). Any future or
alternate writer of the automatic_item_modification_by_age_configuration
syspref would have reopened both holes without touching the form at
all.

This adds the same allow-list validation directly in ToggleNewStatus
(falling back to the safe default agefield, or skipping the
substitution/condition, exactly as before for missing values), shares
the age-field allow-list between the two files via a new
GetAutomaticItemModificationAgeFields() in C4::Items so it can't drift
between them, and logs rejected values via Koha::Logger instead of
silently discarding them so tampering leaves an audit trail.

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:38 +00:00
Jonathan Druart 52f4b17b0f
Bug 42746: Sanitize condition and substitution fields
Signed-off-by: Sanjar Tulkinov Anvar o'g'li <sanjarbiy11@gmail.com>

Amended-by: Jonathan Druart:
Replace , with ;

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:37 +00:00
Jonathan Druart 2b09e846bc
Bug 42746: Sanitize age_field
Signed-off-by: Sanjar Tulkinov Anvar o'g'li <sanjarbiy11@gmail.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:36 +00:00
Martin Renvoize 8145e26a93
Bug 42471: (follow-up) prevent XSS in suggestion status
The custom/authorized-value status branch concatenated row.status
directly into a class="..." attribute string. escape_str() only
escapes &, <, > (not quotes), so a status code containing a double
quote could still break out of the attribute.

Build the status <span> via DOM APIs instead, the same way the
reason field was fixed: fixed statuses get a hardcoded class, and
the free-form status code goes into a data-status attribute via
dataset, which the DOM escapes safely regardless of content.

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:35 +00:00
David Cook 222dac6c3c
Bug 42471: (follow-up) prevent XSS in suggestion reason
Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:34 +00:00
Jonathan Druart acf1184436
Bug 42471: Prevent XSS in suggestion.tt
escape_str all the things

Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:33 +00:00
Martin Renvoize da595ca8d5
Bug 30233: (follow-up) Fix POD formatting codes in _apply_substitution
The angle-bracket delimiter notation in the POD prose (e.g.
PATTERN<DELIM>) caused the POD parser to treat the trailing letter of
each word as an unknown formatting code (N<>, T<>). Replace with
C<s/PATTERN/REPLACEMENT/FLAGS> and a parenthetical note that any
non-space delimiter is accepted.

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Baptiste Wojtkowski <baptiste.wojtkowski@biblibre.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:32 +00:00
Martin Renvoize 8a06056143
Bug 30233: (follow-up) Add tests for _apply_substitution and combined modifiers
- t/C4/ClassSplitRoutine/RegEx.t (new): exercises _apply_substitution via
  the public split_callnumber interface — basic substitution, alternate
  delimiters, \n/$n backrefs, /gi combined flag, /e rejection, and malformed
  or uncompilable rules (including the new logger warn path).
- t/Koha/Regex/Replacement.t: extend the subst() helper to handle the ig/gi
  combined modifier and add a subtest that confirms case-insensitive global
  replacement and backref case preservation.

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Baptiste Wojtkowski <baptiste.wojtkowski@biblibre.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:30 +00:00
Martin Renvoize 45852aa193
Bug 30233: (follow-up) Log a warning when _apply_substitution discards a bad pattern
When eval { qr/$pattern/ } fails (e.g. the admin-configured s/// contains
an invalid regex), _apply_substitution previously returned silently with no
indication of why the rule was skipped. Add a Koha::Logger warn so the
failure appears in the log and is diagnosable without a debugger.

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Baptiste Wojtkowski <baptiste.wojtkowski@biblibre.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:29 +00:00