This patch addresses the circular dependency issues and code quality
concerns identified in QA by introducing a clean architectural solution.
Changes:
1. Created Koha::Plugins::Loader - A lightweight plugin loader with
minimal dependencies that can be safely called during early
initialization. Uses DBIx::Class when available for proper
transaction support, falls back to raw DBI for early init.
2. Added Koha::Database::table_exists() - Consolidated table checking
logic into a reusable method that can be called as both class and
instance method.
3. Simplified C4::Context BEGIN block - Reduced from ~120 lines to
~13 lines (91% reduction). Removed XML::Simple dependency and
manual database connection code.
4. Updated Koha::Plugins::get_enabled_plugins() - Now delegates to
the Loader module for consistency.
5. Updated C4::Installer::TableExists - Delegates to the new
Koha::Database::table_exists method.
This addresses all QA concerns:
- Eliminates XML::Simple usage (David Cook)
- Uses Koha::Database instead of manual DBI (David Cook)
- Reuses table checking logic (Nick Clemens)
- Eliminates circular dependencies (Paul Derscheid)
- Much cleaner and maintainable code
Test plan:
1. Run tests:
prove t/db_dependent/Koha/Database.t
prove t/db_dependent/Koha/Plugins/Loader.t
prove t/db_dependent/Koha/Plugins/Plugins.t
2. All tests should pass
3. Install and enable a plugin via the UI
4. Verify plugin hooks are called correctly
5. Verify no regressions in plugin functionality
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
To test:
1 - try to receive an item, get an error loading items to receive
2 - apply patch, restart
3 - reload page, it works!
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
- I think "Please enter a card number or name" sounds friendlier
- We don't add a "btn-primary" class to these buttons
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
If the "arrow" button on the patron search is clicked with no value in
the textbox, it redirects to members/members-home.pl and performs a
search with no value automatically. It makes more send for it to behave
as the "Patrons" link in the navbar that directs to members-home.pl
where the librarian can then perform a more advanced search.
Test Plan:
1) Click the "Search patrons" link on the header, then the arrow button
2) Note an empty patron search is performed immediately
3) Apply this patch
4) Restart all the things!
5) Repeat step 1
6) Note a paton search is no longer triggered automatically
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This commit adds the missing accesskey attribute to the print button in the circulation template.
Test plan:
1. Try to checkout an item that is waiting for pickup.
2. Try to print the checkout receipt using the alt+shift+p keyboard shortcut.
3. Verify that nothing happens when using the shortcut.
4. After applying this commit, try the same steps again.
5. Verify that the print button now works with the alt+shift+p keyboard shortcut.
Sponsored-by: Koha-Suomi Oy
Signed-off-by: Slava Shishkin <slavashishkin@gmail.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
When checking in an item that has both a hold and a stock rotation
repatriation transfer, both modals would appear simultaneously,
overlapping each other and making it impossible to interact with
either one properly.
This occurred because:
1. The hold modal showed when 'waiting' was set
2. The transfer modal condition checked for 'reserved' but not 'waiting'
3. Both modals had the "block" class, causing simultaneous display
This patch ensures holds take precedence over stock rotation transfers
by adding a check for the 'waiting' flag to the transfer modal condition.
When a hold is found, only the hold modal displays. The stock rotation
transfer can be handled at a subsequent check-in, which is appropriate
since holds are patron-facing and time-sensitive, while stock rotation
is an internal process that can be deferred.
Test plan:
1. Enable StockRotation system preference
2. Navigate to Cataloging->Stock rotation
3. Click '+ New rota' and fill out with any values
4. Click 'Manage->stages' for the Rota
5. Add a stage for Centerville for 1 day, and Midway for 1 day
6. Return to rotas
7. Click Manage->items for the rota
8. Add an item
9. Return to rotas
10. Click 'Activate'
11. On the command line run the stock rotation job:
perl misc/cronjobs/stockrotation.pl -x
12. There should be one item for initiation
13. Run it again, there should be one stationary item
14. Place an item specific hold for the item, for pickup at Midway
15. Check the item in at Centerville, confirm transfer
16. Check the item in at Midway, confirm hold
17. Run the stock rotation job again:
perl misc/cronjobs/stockrotation.pl -x
18. There should be one item for repatriation
19. Check in the item again at Midway
20. Before patch: Two overlapping modals appear (hold + transfer)
21. After patch: Only the hold modal appears
22. Confirm the hold - no transfer modal should appear
23. The stock rotation transfer will be handled at the next check-in
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
It has been removed in the controller by the previous patch.
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This patch forces download of invoice files rather than showing
them inline where they can potentially perform XSS
Test plan:
0. Apply the patch
1. koha-plack --restart kohadev
2. Find or create an active vendor
3. Create a basket if one doesn't already exist
4. Receive a shipment for the vendor
5. Create an invoice
6. Go to the invoice
7. In the URL change invoice.pl to invoice-files.pl
(or turn on AcqEnableFiles and go to it that way)
8. Upload an image file (e.g. SVG) or PDF
9. Click on the filename
10. Note that instead of displaying in the browser,
the file will be downloaded
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Fix error:
[2026/02/11 09:18:00] [WARN] XSLT::Base: runtime error: file /usr/share/koha/opac/htdocs/opac-tmpl/bootstrap/en/xslt/MARC21slimUtils.xsl line 726 element choose
Variable 'URLLinkText' has not been declared.
Undefined variable
at /usr/share/koha/lib/Koha/XSLT/Base.pm line 231.
Run tests to prove the patch fixes the issue (this fails before the patch):
prove t/db_dependent/Search.t
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
ERM/Titles_spec.ts fails if run after ERM/Dialog_spec.ts because Dialog's "...created!" test create a package and does not delete it.
02:48:52 koha-1 | <failure message="Timed out retrying after 10000ms: Expected to find content: 'There are no packages created yet' within the element: <fieldset#resources_relationship.rows> but never did." type="AssertionError"><![CDATA[AssertionError: Timed out retrying after 10000ms: Expected to find content: 'There are no packages created yet' within the element: <fieldset#resources_relationship.rows> but never did.
Test plan:
0. Do not apply the patch
1. yarn cypress run --spec t/cypress/integration/ERM/Dialog_spec.ts,t/cypress/integration/ERM/Titles_spec.ts
=> FAIL
2. Notice that one entry has been created in the DB table erm_eholdings_packages
3. Delete the DB entry:
sudo koha-mysql kohadev -e 'DELETE FROM erm_eholdings_packages'
4. Apply this patch
5. Repeat 1
=> SUCCESS
6. Notice that no new entry has been created in erm_eholdings_packages
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Fix the following error:
Error: The following error originated from your application code, not from Cypress. It was caused by an unhandled promise rejection.
> JS Warning detected: "[Vue warn]: Unhandled error during execution of watcher callback" "\n" " at <AdditionalFieldsEntry"
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This code injected the csrf token using the TT include file, that made
pass xt/find-missing-csrf.t
This bug removed the TT tags from the script tags, and we now need to
use a JS variable and retrieve the csrf token from the meta tag.
This patch suggests to adjust the script to ignore this case. We could
also rewrite the whole JS code and use built the HTML elements using
vanilla JS but that's for another day...
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
The renderMARCOnlineResourceField template uses $biblionumber for the
TrackClicks feature but this parameter was never declared in the template
definition nor passed by any of the call sites.
This caused XSLT runtime errors when TrackClicks system preference is
enabled ('track' or 'anonymous') and records contain MARC fields 856 or
857 with subfield $u (URLs):
Variable 'biblionumber' has not been declared.
Undefined variable
XPath evaluation returned no result.
This patch:
1. Adds biblionumber parameter to renderMARCOnlineResourceField template
2. Passes biblionumber value in all 4 call sites (2 in Detail, 2 in Results)
Test plan:
1. Enable TrackClicks: System Preferences > OPAC > TrackClicks = "track"
2. Find a bibliographic record with field 856 or 857 containing subfield $u
3. Run: yarn build (to regenerate XSLT for all languages)
4. View the record in OPAC detail and search results pages
5. Verify no XSLT errors in plack-opac-error.log
6. Verify online resource links display correctly
7. Verify links include biblionumber parameter in tracklinks.pl URLs
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Clicking on New data provider in the ERM eUsage section will not work, when a data provider was shown before.
Test plan:
prequisites:
- activate the ERM module system preference.
- this is for ktd
a) go to /cgi-bin/koha/erm/eusage/usage_data_providers
b) add a new data provider, dummy data is sufficient
c) submit the new provider and on the following screen click close to return to the provider list
d) click on 'Add data provider' (open web dev tools will display an error)
e) apply patch
f) run 'yarn js:build'
f) do a hard refresh in the browser
g) on provider list click your created provider
h) close it via 'close' to return to the provider list
d) click on 'Add data provider' should work now
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This patch prevents deletion of items that have item level holds on
them.
Test plan:
1. Create an item level hold.
2. Delete the item using alternative A or B:
A. Open the biblios Detail-view -> From the toolbar, open
"Edit"-dropdown menu -> Manage items -> Delete the item that has
an item level hold attached to it from "Actions"-dropdown menu
B. Open the biblios Detail-view -> Select the item that has an item
level hold attached to it -> Click "Delete selected items" ->
Confirm deletion
3. Notice that the item is deleted without any warning and the item
level hold has disappeared.
4. Apply this patch.
5. Repeat steps 1-3.
6. Notice that the item cannot be deleted and a warning is shown.
7. prove t/db_dependent/Koha/Item.t
8. Run the REST API tests: prove t/db_dependent/api/v1/items.t
Sponsored-by: Koha-Suomi Oy
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
See bug 41324 comment 6
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
See bug 41324 comment 6
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
See bug 41324 comment 6
1. Variable serialization
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Not caused by this patchset but it's a good place to fix it (and not add
a conflict)
Uncaught TypeError: can't access property "DataTable", suggestionst is undefined
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>