Merge branch '24.11.x-security' into 24.11.x
This commit is contained in:
commit
13fe0cbf0e
|
|
@ -1739,8 +1739,14 @@ sub _process_tt {
|
|||
my $use_template_cache = C4::Context->config('template_cache_dir') && defined $ENV{GATEWAY_INTERFACE};
|
||||
my $template = Template->new(
|
||||
{
|
||||
EVAL_PERL => 0,
|
||||
ABSOLUTE => 0,
|
||||
EVAL_PERL => 0,
|
||||
ABSOLUTE => 0,
|
||||
RELATIVE => 0,
|
||||
PLUGINS => {
|
||||
cgi => 'Koha::Template::Plugin::noop',
|
||||
directory => 'Koha::Template::Plugin::noop',
|
||||
file => 'Koha::Template::Plugin::noop',
|
||||
},
|
||||
PLUGIN_BASE => 'Koha::Template::Plugin',
|
||||
COMPILE_EXT => $use_template_cache ? '.ttc' : '',
|
||||
COMPILE_DIR => $use_template_cache ? C4::Context->config('template_cache_dir') : '',
|
||||
|
|
|
|||
2
Koha.pm
2
Koha.pm
|
|
@ -29,7 +29,7 @@ use vars qw{ $VERSION };
|
|||
# - #4 : the developer version. The 4th number is the database subversion.
|
||||
# used by developers when the database changes. updatedatabase take care of the changes itself
|
||||
# and is automatically called by Auth.pm when needed.
|
||||
$VERSION = "24.11.14.000";
|
||||
$VERSION = "24.11.15.000";
|
||||
|
||||
sub version {
|
||||
return $VERSION;
|
||||
|
|
|
|||
|
|
@ -120,23 +120,46 @@ sub new {
|
|||
|
||||
=head3 fixup_cardnumber
|
||||
|
||||
Autogenerate next cardnumber from highest value found in database
|
||||
Autogenerate next cardnumber from highest value found in database.
|
||||
|
||||
Uses the C<autoMemberNumValue> system preference as a monotonic floor so a
|
||||
cardnumber is never re-issued after the original holder's cardnumber has been
|
||||
changed or their account deleted. The syspref row is selected C<FOR UPDATE>
|
||||
inside the enclosing transaction so that concurrent C<store()> callers are
|
||||
serialised.
|
||||
|
||||
=cut
|
||||
|
||||
sub fixup_cardnumber {
|
||||
my ( $self ) = @_;
|
||||
|
||||
my $max = $self->cardnumber;
|
||||
Koha::Plugins->call( 'patron_barcode_transform', \$max );
|
||||
my $next = $self->cardnumber;
|
||||
Koha::Plugins->call( 'patron_barcode_transform', \$next );
|
||||
|
||||
$max ||= Koha::Patrons->search({
|
||||
cardnumber => {-regexp => '^-?[0-9]+$'}
|
||||
}, {
|
||||
select => \'CAST(cardnumber AS SIGNED)',
|
||||
as => ['cast_cardnumber']
|
||||
})->_resultset->get_column('cast_cardnumber')->max;
|
||||
$self->cardnumber(($max || 0) +1);
|
||||
# Only auto-generate when no cardnumber has been supplied (directly or by a plugin).
|
||||
unless ($next) {
|
||||
my $schema = $self->_result->result_source->schema;
|
||||
my $pref_rs = $schema->resultset('Systempreference')->search(
|
||||
{ variable => 'autoMemberNumValue' },
|
||||
{ for => 'update' },
|
||||
);
|
||||
my $pref = $pref_rs->first;
|
||||
my $counter = ( $pref && $pref->value ) || 0;
|
||||
|
||||
my $db_max = Koha::Patrons->search(
|
||||
{ cardnumber => { -regexp => '^-?[0-9]+$' } },
|
||||
{
|
||||
select => \'CAST(cardnumber AS SIGNED)',
|
||||
as => ['cast_cardnumber'],
|
||||
}
|
||||
)->_resultset->get_column('cast_cardnumber')->max
|
||||
|| 0;
|
||||
|
||||
$next = ( $counter > $db_max ? $counter : $db_max ) + 1;
|
||||
$pref->update( { value => $next } ) if $pref;
|
||||
}
|
||||
|
||||
$self->cardnumber($next);
|
||||
}
|
||||
|
||||
=head3 trim_whitespace
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
package Koha::Template::Plugin::noop;
|
||||
|
||||
use Modern::Perl;
|
||||
|
||||
use base qw( Template::Plugin );
|
||||
|
||||
1;
|
||||
|
|
@ -61,8 +61,14 @@ sub process_tt {
|
|||
|
||||
my $tt = Template->new(
|
||||
{
|
||||
EVAL_PERL => 0,
|
||||
ABSOLUTE => 0,
|
||||
EVAL_PERL => 0,
|
||||
ABSOLUTE => 0,
|
||||
RELATIVE => 0,
|
||||
PLUGINS => {
|
||||
cgi => 'Koha::Template::Plugin::noop',
|
||||
directory => 'Koha::Template::Plugin::noop',
|
||||
file => 'Koha::Template::Plugin::noop',
|
||||
},
|
||||
PLUGIN_BASE => 'Koha::Template::Plugin',
|
||||
COMPILE_EXT => $use_template_cache ? '.ttc' : '',
|
||||
COMPILE_DIR => $use_template_cache ? C4::Context->config('template_cache_dir') : '',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
use Modern::Perl;
|
||||
use Koha::Installer::Output qw(say_warning say_success say_info);
|
||||
|
||||
return {
|
||||
bug_number => "34000",
|
||||
description => "Prevent re-issuance of auto-generated cardnumbers",
|
||||
up => sub {
|
||||
my ($args) = @_;
|
||||
my ( $dbh, $out ) = @$args{qw(dbh out)};
|
||||
|
||||
my $exists = $dbh->selectrow_array(q{SELECT 1 FROM systempreferences WHERE variable = 'autoMemberNumValue'});
|
||||
|
||||
if ($exists) {
|
||||
say_warning( $out, "System preference 'autoMemberNumValue' already exists, skipping" );
|
||||
return;
|
||||
}
|
||||
|
||||
# Seed from the highest numeric cardnumber ever issued, considering both live
|
||||
# and deleted patrons so pre-upgrade deletions don't free up their numbers.
|
||||
my ($seed) = $dbh->selectrow_array(
|
||||
q{
|
||||
SELECT COALESCE(
|
||||
GREATEST(
|
||||
COALESCE(
|
||||
(SELECT MAX(CAST(cardnumber AS SIGNED)) FROM borrowers
|
||||
WHERE cardnumber REGEXP '^-?[0-9]+$'),
|
||||
0
|
||||
),
|
||||
COALESCE(
|
||||
(SELECT MAX(CAST(cardnumber AS SIGNED)) FROM deletedborrowers
|
||||
WHERE cardnumber REGEXP '^-?[0-9]+$'),
|
||||
0
|
||||
)
|
||||
),
|
||||
0
|
||||
)
|
||||
}
|
||||
);
|
||||
$seed //= 0;
|
||||
|
||||
$dbh->do(
|
||||
q{INSERT IGNORE INTO systempreferences (variable, value) VALUES ('autoMemberNumValue', ?)},
|
||||
undef, $seed
|
||||
);
|
||||
|
||||
say_success( $out, "Added new system preference 'autoMemberNumValue' seeded to $seed" );
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
use Modern::Perl;
|
||||
|
||||
return {
|
||||
bug_number => undef,
|
||||
description => 'Koha 24.11.15 release',
|
||||
up => sub { },
|
||||
};
|
||||
|
|
@ -97,7 +97,8 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `
|
|||
('AutomaticCheckinAutoFill','0',NULL,'Automatically fill the next hold with an automatic check in.','YesNo'),
|
||||
('AutomaticConfirmTransfer','0',NULL,'Defines whether transfers should be automatically confirmed at checkin if modal dismissed','YesNo'),
|
||||
('AutomaticItemReturn','1',NULL,'If ON, Koha will automatically set up a transfer of this item to its homebranch','YesNo'),
|
||||
('autoMemberNum','0','','If ON, patron number is auto-calculated','YesNo'),
|
||||
('autoMemberNum','0',NULL,'If ON, patron number is auto-calculated','YesNo'),
|
||||
('autoMemberNumValue','0',NULL,'Stores the last auto-generated cardnumber to prevent re-issuance','Integer'),
|
||||
('AutoRemoveOverduesRestrictions','no','no|when_no_overdue|when_no_overdue_causing_debarment', 'Defines if and on what conditions OVERDUES debarments should automatically be lifted when overdue items are returned by the patron.','Choice'),
|
||||
('AutoRenewalNotices','preferences','cron|preferences|never','How should Koha determine whether to end autorenewal notices','Choice'),
|
||||
('AutoResumeSuspendedHolds','1',NULL,'Allow suspended holds to be automatically resumed by a set date.','YesNo'),
|
||||
|
|
|
|||
|
|
@ -773,7 +773,7 @@ require( [ 'koha-backend', 'search', 'macros', 'marc-editor', 'marc-record', 'pr
|
|||
macroEditor.setValue( '' );
|
||||
return;
|
||||
}
|
||||
$( '#macro-list li[data-name="' + name + '"][data-id="' + id + '"]' ).addClass( 'active' );
|
||||
$( '#macro-list li[data-id="' + id + '"]' ).addClass( 'active' );
|
||||
api_url = "/api/v1/advanced_editor/macros/";
|
||||
if( shared ) { api_url += "shared/" }
|
||||
let options = {
|
||||
|
|
@ -878,7 +878,8 @@ require( [ 'koha-backend', 'search', 'macros', 'marc-editor', 'marc-record', 'pr
|
|||
$.ajax(options)
|
||||
.then(function(result) {
|
||||
$.each(result,function( undef, macro ){
|
||||
var $li = $( '<li data-name="' + macro.name + '" data-id="' + macro.macro_id + '"><a href="#">' + macro.name + '</a><ol class="macro-info"></ol></li>' );
|
||||
var $li = $( '<li data-id="' + macro.macro_id + '"><a href="#">' + escape_str(macro.name) + '</a><ol class="macro-info"></ol></li>' );
|
||||
$li.get(0).setAttribute('data-name',macro.name);
|
||||
if ( macro.macro_id == macroEditor.activeMacroId ) $li.addClass( 'active' );
|
||||
$li.click( function() {
|
||||
loadMacro(macro.name, macro.macro_id, macro.shared);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
review_ajax_params = {
|
||||
url: "/cgi-bin/koha/tags/review.pl",
|
||||
dataType: "script"
|
||||
dataType: "json",
|
||||
};
|
||||
|
||||
var ok_count = 0;
|
||||
|
|
@ -14,7 +14,12 @@ function pull_counts () {
|
|||
rej_count = parseInt(document.getElementById("terms_summary_rejected_count" ).innerHTML);
|
||||
}
|
||||
|
||||
function count_approve () {
|
||||
function count_approve(response) {
|
||||
if (response.status == "success") {
|
||||
//success_approve(response.tag);
|
||||
} else {
|
||||
failure_approve(response.tag);
|
||||
}
|
||||
pull_counts();
|
||||
if (nok_count > 0) {
|
||||
$("#terms_summary_unapproved_count").html(nok_count -1);
|
||||
|
|
@ -22,7 +27,12 @@ function count_approve () {
|
|||
}
|
||||
}
|
||||
|
||||
function count_reject () {
|
||||
function count_reject(response) {
|
||||
if (response.status == "success") {
|
||||
//success_reject(response.tag);
|
||||
} else {
|
||||
failure_reject(response.tag);
|
||||
}
|
||||
pull_counts();
|
||||
if (nok_count > 0) {
|
||||
$("#terms_summary_unapproved_count").html(nok_count -1);
|
||||
|
|
@ -30,31 +40,51 @@ function count_reject () {
|
|||
}
|
||||
}
|
||||
|
||||
var success_approve = function(tag){
|
||||
// window.alert(__("AJAX approved tag: ") + tag);
|
||||
//var success_approve = function (tag) {
|
||||
// window.alert(__("AJAX approved tag: ") + tag);
|
||||
//};
|
||||
var failure_approve = function (tag) {
|
||||
window.alert(__("AJAX failed to approve tag: %s").format(escape_str(tag)));
|
||||
};
|
||||
var failure_approve = function(tag){
|
||||
window.alert( __("AJAX failed to approve tag: %s").format(decodeURIComponent(tag)) );
|
||||
//var success_reject = function (tag) {
|
||||
// window.alert(__("AJAX rejected tag: ") + tag);
|
||||
//};
|
||||
var failure_reject = function (tag) {
|
||||
window.alert(__("AJAX failed to reject tag: %s").format(escape_str(tag)));
|
||||
};
|
||||
var success_reject = function(tag){
|
||||
// window.alert(__("AJAX rejected tag: ") + tag);
|
||||
var success_test = function (tag) {
|
||||
const verdict = document.querySelector("#verdict");
|
||||
if (verdict) {
|
||||
verdict.textContent = __("%s is permitted!").format(tag);
|
||||
}
|
||||
};
|
||||
var failure_reject = function(tag){
|
||||
window.alert( __("AJAX failed to reject tag: %s").format(decodeURIComponent(tag)) );
|
||||
var failure_test = function (tag) {
|
||||
const verdict = document.querySelector("#verdict");
|
||||
if (verdict) {
|
||||
verdict.textContent = __("%s is prohibited!").format(tag);
|
||||
}
|
||||
};
|
||||
var success_test = function(tag){
|
||||
$('#verdict').html( __("%s is permitted!").format(decodeURIComponent(tag)) );
|
||||
};
|
||||
var failure_test = function(tag){
|
||||
$('#verdict').html( __("%s is prohibited!").format(decodeURIComponent(tag)) );
|
||||
};
|
||||
var indeterminate_test = function(tag){
|
||||
$('#verdict').html( __("%s is neither permitted nor prohibited!").format(decodeURIComponent(tag)) );
|
||||
var indeterminate_test = function (tag) {
|
||||
const verdict = document.querySelector("#verdict");
|
||||
if (verdict) {
|
||||
verdict.textContent = __(
|
||||
"%s is neither permitted nor prohibited!"
|
||||
).format(tag);
|
||||
}
|
||||
};
|
||||
|
||||
var success_test_call = function() {
|
||||
$('#test_button').prop('disabled', false);
|
||||
$('#test_button').html("<i class='fa fa-check-square' aria-hidden='true'></i>" +__(" Test"));
|
||||
var success_test_call = function (response) {
|
||||
if (response.status == "success") {
|
||||
success_test(response.tag);
|
||||
} else if (response.status == "failure") {
|
||||
failure_test(response.tag);
|
||||
} else {
|
||||
indeterminate_test(response.tag);
|
||||
}
|
||||
$("#test_button").prop("disabled", false);
|
||||
$("#test_button").html(
|
||||
"<i class='fa fa-check-square' aria-hidden='true'></i>" + __(" Test")
|
||||
);
|
||||
};
|
||||
|
||||
$(document).ready(function() {
|
||||
|
|
@ -155,7 +185,7 @@ $(document).ready(function() {
|
|||
{ ...review_ajax_params, type: "GET" },
|
||||
{
|
||||
data: {
|
||||
tag: escape_str($("#test").val()),
|
||||
tag: $("#test").val(),
|
||||
op: "test",
|
||||
},
|
||||
success: success_test_call, // success_reject
|
||||
|
|
|
|||
|
|
@ -998,9 +998,9 @@ $(function() {
|
|||
var shelf_number = $(this).data("shelfnumber");
|
||||
var is_shared = $(this).data("shared");
|
||||
var count = $(this).data("count");
|
||||
var message = "<p><em>" + shelf_name + "</em></p>";
|
||||
var message = "<p><em>" + escape_str(shelf_name) + "</em></p>";
|
||||
if( count ){
|
||||
message += "<p>" + _("Items on this list:") + " <strong>" + count + "</strong></p>";
|
||||
message += "<p>" + _("Items on this list:") + " <strong>" + escape_str(count) + "</strong></p>";
|
||||
}
|
||||
if( is_shared ){
|
||||
message += "<p>" + _("This list is shared. Other users will lose access to it.") + "</p>";
|
||||
|
|
@ -1017,7 +1017,7 @@ $(function() {
|
|||
e.preventDefault();
|
||||
var shelf_name = $(this).data("shelfname");
|
||||
var shelf_number = $(this).data("shelfnumber");
|
||||
confirmModal( shelf_name, _("Are you sure you want to remove sharing? You will no longer have access to the list."), _("Yes, remove sharing"), _("No, do not remove sharing"), function( result ){
|
||||
confirmModal( escape_str(shelf_name), _("Are you sure you want to remove sharing? You will no longer have access to the list."), _("Yes, remove sharing"), _("No, do not remove sharing"), function( result ){
|
||||
if( result ){
|
||||
$("#unshare" + shelf_number ).submit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,286 @@
|
|||
<h1 id="releasenotesforkoha24.11.15">RELEASE NOTES FOR KOHA 24.11.15</h1>
|
||||
|
||||
<p>22 Apr 2026</p>
|
||||
|
||||
<p>Koha is the first free and open source software library automation
|
||||
package (ILS). Development is sponsored by libraries of varying types
|
||||
and sizes, volunteers, and support companies from around the world. The
|
||||
website for the Koha project is:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://koha-community.org">Koha Community</a></li>
|
||||
</ul>
|
||||
|
||||
<p>Koha 24.11.15 can be downloaded from:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://download.koha-community.org/koha-24.11.15.tar.gz">Download</a></li>
|
||||
</ul>
|
||||
|
||||
<p>Installation instructions can be found at:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://wiki.koha-community.org/wiki/Installation_Documentation">Koha Wiki</a></li>
|
||||
<li>OR in the INSTALL files that come in the tarball</li>
|
||||
</ul>
|
||||
|
||||
<p>Koha 24.11.15 is a bugfix/maintenance release.</p>
|
||||
|
||||
<p>It includes 2 enhancements, 4 bugfixes.</p>
|
||||
|
||||
<p><strong>System requirements</strong></p>
|
||||
|
||||
<p>You can learn about the system components (like OS and database) needed for running Koha on the <a href="https://wiki.koha-community.org/wiki/System_requirements_and_recommendations">community wiki</a>.</p>
|
||||
|
||||
<h4 id="securitybugs">Security bugs</h4>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=34000">34000</a> Don't allow auto-generated cardnumbers to be re-used, it may give access of services to the next patron created</li>
|
||||
<li><a href="https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42136">42136</a> User-entered Template::Toolkit allows information disclosure</li>
|
||||
<li><a href="https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42252">42252</a> Stored XSS when deleting a list or removing a list share</li>
|
||||
<li><a href="https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42253">42253</a> Stored XSS in advanced editor in Macro name</li>
|
||||
<li><a href="https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42254">42254</a> DOM XSS via tag search</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="bugfixes">Bugfixes</h2>
|
||||
|
||||
<h2 id="enhancements">Enhancements</h2>
|
||||
|
||||
<h3 id="continuousintegration">Continuous Integration</h3>
|
||||
|
||||
<h4 id="enhancements">Enhancements</h4>
|
||||
|
||||
<p><ul>
|
||||
<li><a href="https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=41368">41368</a> Tools/ManageMarcImport_spec.ts is failing</p>
|
||||
|
||||
<blockquote>
|
||||
<p>26.05.00</li>
|
||||
</ul></p>
|
||||
|
||||
<h2 id="newsystempreferences">New system preferences</h2>
|
||||
</blockquote>
|
||||
|
||||
<ul>
|
||||
<li>autoMemberNumValue</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="documentation">Documentation</h2>
|
||||
|
||||
<p>The Koha manual is maintained in Sphinx. The home page for Koha
|
||||
documentation is</p>
|
||||
|
||||
<ul>
|
||||
<li><p><a href="https://koha-community.org/documentation/">Koha Documentation</a>
|
||||
As of the date of these release notes, the Koha manual is available in the following languages:</p></li>
|
||||
<li><p><a href="https://koha-community.org/manual/24.11/en/html/">English (USA)</a></p></li>
|
||||
<li><a href="https://koha-community.org/manual/24.11/fr/html/">French</a> (80%)</li>
|
||||
<li><a href="https://koha-community.org/manual/24.11/de/html/">German</a> (89%)</li>
|
||||
<li><a href="https://koha-community.org/manual/24.11/el/html/">Greek</a> (93%)</li>
|
||||
<li><a href="https://koha-community.org/manual/24.11/hi/html/">Hindi</a> (63%)</li>
|
||||
</ul>
|
||||
|
||||
<p>The Git repository for the Koha manual can be found at</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://gitlab.com/koha-community/koha-manual">Koha Git Repository</a></li>
|
||||
</ul>
|
||||
|
||||
<h2 id="translations">Translations</h2>
|
||||
|
||||
<p>Complete or near-complete translations of the OPAC and staff
|
||||
interface are available in this release for the following languages:</p>
|
||||
|
||||
<div style="column-count: 2;">
|
||||
|
||||
- Arabic (ar_ARAB) (95%)
|
||||
- Armenian (hy_ARMN) (100%)
|
||||
- Bulgarian (bg_CYRL) (100%)
|
||||
- Chinese (Simplified Han script) (86%)
|
||||
- Chinese (Traditional Han script) (99%)
|
||||
- Czech (68%)
|
||||
- Dutch (88%)
|
||||
- English (100%)
|
||||
- English (New Zealand) (63%)
|
||||
- English (USA)
|
||||
- Finnish (99%)
|
||||
- French (100%)
|
||||
- French (Canada) (99%)
|
||||
- German (100%)
|
||||
- Greek (67%)
|
||||
- Hindi (97%)
|
||||
- Italian (83%)
|
||||
- Norwegian Bokmål (73%)
|
||||
- Persian (fa_ARAB) (96%)
|
||||
- Polish (99%)
|
||||
- Portuguese (Brazil) (99%)
|
||||
- Portuguese (Portugal) (88%)
|
||||
- Russian (94%)
|
||||
- Slovak (61%)
|
||||
- Spanish (99%)
|
||||
- Swedish (88%)
|
||||
- Telugu (67%)
|
||||
- Tetum (52%)
|
||||
- Turkish (83%)
|
||||
- Ukrainian (76%)
|
||||
- Western Armenian (hyw_ARMN) (62%)
|
||||
</div>
|
||||
|
||||
<p>Partial translations are available for various other languages.</p>
|
||||
|
||||
<p>The Koha team welcomes additional translations; please see</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://wiki.koha-community.org/wiki/Translating_Koha">Koha Translation Info</a></li>
|
||||
</ul>
|
||||
|
||||
<p>For information about translating Koha, and join the koha-translate
|
||||
list to volunteer:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://lists.koha-community.org/cgi-bin/mailman/listinfo/koha-translate">Koha Translate List</a></li>
|
||||
</ul>
|
||||
|
||||
<p>The most up-to-date translations can be found at:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://translate.koha-community.org/">Koha Translation</a></li>
|
||||
</ul>
|
||||
|
||||
<h2 id="releaseteam">Release Team</h2>
|
||||
|
||||
<p>The release team for Koha 24.11.15 is</p>
|
||||
|
||||
<ul>
|
||||
<li><p>Release Manager: Lucas Gass</p></li>
|
||||
<li><p>QA Manager: Martin Renvoize</p></li>
|
||||
<li><p>QA Team:</p>
|
||||
|
||||
<ul>
|
||||
<li>Marcel de Rooy</li>
|
||||
<li>Martin Renvoize</li>
|
||||
<li>Jonathan Druart</li>
|
||||
<li>Laura Escamilla</li>
|
||||
<li>Lucas Gass</li>
|
||||
<li>Tomás Cohen Arazi</li>
|
||||
<li>Lisette Scheer</li>
|
||||
<li>Nick Clemens</li>
|
||||
<li>Paul Derscheid</li>
|
||||
<li>Emily Lamancusa</li>
|
||||
<li>David Cook</li>
|
||||
<li>Matt Blenkinsop</li>
|
||||
<li>Andrew Fuerste-Henry</li>
|
||||
<li>Brendan Lawlor</li>
|
||||
<li>Pedro Amorim</li>
|
||||
<li>Kyle M Hall</li>
|
||||
<li>Aleisha Amohia</li>
|
||||
<li>David Nind</li>
|
||||
<li>Baptiste Wojtkowski</li>
|
||||
<li>Jan Kissig</li>
|
||||
<li>Katrin Fischer</li>
|
||||
<li>Thomas Klausner</li>
|
||||
<li>Julian Maurice</li>
|
||||
<li>Owen Leonard</li>
|
||||
</ul></li>
|
||||
<li><p>Documentation Manager: David Nind</p></li>
|
||||
<li><p>Documentation Team:</p>
|
||||
|
||||
<ul>
|
||||
<li>Philip Orr</li>
|
||||
<li>Aude Charillon</li>
|
||||
<li>Caroline Cyr La Rose</li>
|
||||
</ul></li>
|
||||
<li><p>Translation Manager: Jonathan Druart</p></li>
|
||||
<li><p>Wiki curators: </p>
|
||||
|
||||
<ul>
|
||||
<li>George Williams</li>
|
||||
<li>Thomas Dukleth</li>
|
||||
</ul></li>
|
||||
<li><p>Release Maintainers:</p>
|
||||
|
||||
<ul>
|
||||
<li>25.11 -- Jacob O'Mara</li>
|
||||
<li>25.05 -- Laura Escamilla</li>
|
||||
<li>24.11 -- Fridolin Somers</li>
|
||||
<li>22.11 -- Wainui Witika-Park (Catalyst IT)</li>
|
||||
</ul></li>
|
||||
<li><p>Release Maintainer assistants:</p>
|
||||
|
||||
<ul>
|
||||
<li>25.11 -- Chloé Zermatten</li>
|
||||
<li>24.11 -- Baptiste Wojtkowski</li>
|
||||
<li>22.11 -- Alex Buckley & Aleisha Amohia</li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
|
||||
<h2 id="credits">Credits</h2>
|
||||
|
||||
<p>We thank the following individuals who contributed patches to Koha 24.11.15</p>
|
||||
|
||||
<div style="column-count: 2;">
|
||||
|
||||
- David Cook (3)
|
||||
- Jonathan Druart (4)
|
||||
- Lucas Gass (1)
|
||||
- Jacob O'Mara (3)
|
||||
- Martin Renvoize (4)
|
||||
- Marcel de Rooy (1)
|
||||
</div>
|
||||
|
||||
<p>We thank the following libraries, companies, and other institutions who contributed
|
||||
patches to Koha 24.11.15</p>
|
||||
|
||||
<div style="column-count: 2;">
|
||||
|
||||
- [ByWater Solutions](https://bywatersolutions.com) (1)
|
||||
- Koha Community Developers (4)
|
||||
- [OpenFifth](https://openfifth.co.uk) (7)
|
||||
- [Prosentient Systems](https://www.prosentient.com.au) (3)
|
||||
- Rijksmuseum, Netherlands (1)
|
||||
</div>
|
||||
|
||||
<p>We also especially thank the following individuals who tested patches
|
||||
for Koha</p>
|
||||
|
||||
<div style="column-count: 2;">
|
||||
|
||||
- Nick Clemens (1)
|
||||
- David Cook (3)
|
||||
- Jonathan Druart (1)
|
||||
- Andrew Fuerste-Henry (3)
|
||||
- Lucas Gass (1)
|
||||
- Brendan Lawlor (1)
|
||||
- David Nind (1)
|
||||
- Jacob O'Mara (13)
|
||||
- Phil Ringnalda (2)
|
||||
- Marcel de Rooy (2)
|
||||
</div>
|
||||
|
||||
<p>We regret any omissions. If a contributor has been inadvertently missed,
|
||||
please send a patch against these release notes to koha-devel@lists.koha-community.org.</p>
|
||||
|
||||
<h2 id="revisioncontrolnotes">Revision control notes</h2>
|
||||
|
||||
<p>The Koha project uses Git for version control. The current development
|
||||
version of Koha can be retrieved by checking out the main branch of:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://git.koha-community.org/koha-community/koha">Koha Git Repository</a></li>
|
||||
</ul>
|
||||
|
||||
<p>The branch for this version of Koha and future bugfixes in this release
|
||||
line is 24.11.x-security.</p>
|
||||
|
||||
<h2 id="bugsandfeaturerequests">Bugs and feature requests</h2>
|
||||
|
||||
<p>Bug reports and feature requests can be filed at the Koha bug
|
||||
tracker at:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://bugs.koha-community.org">Koha Bugzilla</a></li>
|
||||
</ul>
|
||||
|
||||
<p>He rau ringa e oti ai.
|
||||
(Many hands finish the work)</p>
|
||||
|
||||
<p>Autogenerated release notes updated last on 22 Apr 2026 19:35:08.</p>
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
# RELEASE NOTES FOR KOHA 24.11.15
|
||||
22 Apr 2026
|
||||
|
||||
Koha is the first free and open source software library automation
|
||||
package (ILS). Development is sponsored by libraries of varying types
|
||||
and sizes, volunteers, and support companies from around the world. The
|
||||
website for the Koha project is:
|
||||
|
||||
- [Koha Community](https://koha-community.org)
|
||||
|
||||
Koha 24.11.15 can be downloaded from:
|
||||
|
||||
- [Download](https://download.koha-community.org/koha-24.11.15.tar.gz)
|
||||
|
||||
Installation instructions can be found at:
|
||||
|
||||
- [Koha Wiki](https://wiki.koha-community.org/wiki/Installation_Documentation)
|
||||
- OR in the INSTALL files that come in the tarball
|
||||
|
||||
Koha 24.11.15 is a bugfix/maintenance release.
|
||||
|
||||
It includes 2 enhancements, 4 bugfixes.
|
||||
|
||||
**System requirements**
|
||||
|
||||
You can learn about the system components (like OS and database) needed for running Koha on the [community wiki](https://wiki.koha-community.org/wiki/System_requirements_and_recommendations).
|
||||
|
||||
|
||||
#### Security bugs
|
||||
|
||||
- [34000](https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=34000) Don't allow auto-generated cardnumbers to be re-used, it may give access of services to the next patron created
|
||||
- [42136](https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42136) User-entered Template::Toolkit allows information disclosure
|
||||
- [42252](https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42252) Stored XSS when deleting a list or removing a list share
|
||||
- [42253](https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42253) Stored XSS in advanced editor in Macro name
|
||||
- [42254](https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42254) DOM XSS via tag search
|
||||
|
||||
## Bugfixes
|
||||
|
||||
## Enhancements
|
||||
|
||||
### Continuous Integration
|
||||
|
||||
#### Enhancements
|
||||
|
||||
- [41368](https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=41368) Tools/ManageMarcImport_spec.ts is failing
|
||||
>26.05.00
|
||||
|
||||
## New system preferences
|
||||
|
||||
- autoMemberNumValue
|
||||
|
||||
## Documentation
|
||||
|
||||
The Koha manual is maintained in Sphinx. The home page for Koha
|
||||
documentation is
|
||||
|
||||
- [Koha Documentation](https://koha-community.org/documentation/)
|
||||
As of the date of these release notes, the Koha manual is available in the following languages:
|
||||
|
||||
- [English (USA)](https://koha-community.org/manual/24.11/en/html/)
|
||||
- [French](https://koha-community.org/manual/24.11/fr/html/) (80%)
|
||||
- [German](https://koha-community.org/manual/24.11/de/html/) (89%)
|
||||
- [Greek](https://koha-community.org/manual/24.11/el/html/) (93%)
|
||||
- [Hindi](https://koha-community.org/manual/24.11/hi/html/) (63%)
|
||||
|
||||
The Git repository for the Koha manual can be found at
|
||||
|
||||
- [Koha Git Repository](https://gitlab.com/koha-community/koha-manual)
|
||||
|
||||
## Translations
|
||||
|
||||
Complete or near-complete translations of the OPAC and staff
|
||||
interface are available in this release for the following languages:
|
||||
<div style="column-count: 2;">
|
||||
|
||||
- Arabic (ar_ARAB) (95%)
|
||||
- Armenian (hy_ARMN) (100%)
|
||||
- Bulgarian (bg_CYRL) (100%)
|
||||
- Chinese (Simplified Han script) (86%)
|
||||
- Chinese (Traditional Han script) (99%)
|
||||
- Czech (68%)
|
||||
- Dutch (88%)
|
||||
- English (100%)
|
||||
- English (New Zealand) (63%)
|
||||
- English (USA)
|
||||
- Finnish (99%)
|
||||
- French (100%)
|
||||
- French (Canada) (99%)
|
||||
- German (100%)
|
||||
- Greek (67%)
|
||||
- Hindi (97%)
|
||||
- Italian (83%)
|
||||
- Norwegian Bokmål (73%)
|
||||
- Persian (fa_ARAB) (96%)
|
||||
- Polish (99%)
|
||||
- Portuguese (Brazil) (99%)
|
||||
- Portuguese (Portugal) (88%)
|
||||
- Russian (94%)
|
||||
- Slovak (61%)
|
||||
- Spanish (99%)
|
||||
- Swedish (88%)
|
||||
- Telugu (67%)
|
||||
- Tetum (52%)
|
||||
- Turkish (83%)
|
||||
- Ukrainian (76%)
|
||||
- Western Armenian (hyw_ARMN) (62%)
|
||||
</div>
|
||||
|
||||
Partial translations are available for various other languages.
|
||||
|
||||
The Koha team welcomes additional translations; please see
|
||||
|
||||
- [Koha Translation Info](https://wiki.koha-community.org/wiki/Translating_Koha)
|
||||
|
||||
For information about translating Koha, and join the koha-translate
|
||||
list to volunteer:
|
||||
|
||||
- [Koha Translate List](https://lists.koha-community.org/cgi-bin/mailman/listinfo/koha-translate)
|
||||
|
||||
The most up-to-date translations can be found at:
|
||||
|
||||
- [Koha Translation](https://translate.koha-community.org/)
|
||||
|
||||
## Release Team
|
||||
|
||||
The release team for Koha 24.11.15 is
|
||||
|
||||
|
||||
- Release Manager: Lucas Gass
|
||||
|
||||
- QA Manager: Martin Renvoize
|
||||
|
||||
- QA Team:
|
||||
- Marcel de Rooy
|
||||
- Martin Renvoize
|
||||
- Jonathan Druart
|
||||
- Laura Escamilla
|
||||
- Lucas Gass
|
||||
- Tomás Cohen Arazi
|
||||
- Lisette Scheer
|
||||
- Nick Clemens
|
||||
- Paul Derscheid
|
||||
- Emily Lamancusa
|
||||
- David Cook
|
||||
- Matt Blenkinsop
|
||||
- Andrew Fuerste-Henry
|
||||
- Brendan Lawlor
|
||||
- Pedro Amorim
|
||||
- Kyle M Hall
|
||||
- Aleisha Amohia
|
||||
- David Nind
|
||||
- Baptiste Wojtkowski
|
||||
- Jan Kissig
|
||||
- Katrin Fischer
|
||||
- Thomas Klausner
|
||||
- Julian Maurice
|
||||
- Owen Leonard
|
||||
|
||||
- Documentation Manager: David Nind
|
||||
|
||||
- Documentation Team:
|
||||
- Philip Orr
|
||||
- Aude Charillon
|
||||
- Caroline Cyr La Rose
|
||||
|
||||
- Translation Manager: Jonathan Druart
|
||||
|
||||
|
||||
- Wiki curators:
|
||||
- George Williams
|
||||
- Thomas Dukleth
|
||||
|
||||
- Release Maintainers:
|
||||
- 25.11 -- Jacob O'Mara
|
||||
- 25.05 -- Laura Escamilla
|
||||
- 24.11 -- Fridolin Somers
|
||||
- 22.11 -- Wainui Witika-Park (Catalyst IT)
|
||||
|
||||
- Release Maintainer assistants:
|
||||
- 25.11 -- Chloé Zermatten
|
||||
- 24.11 -- Baptiste Wojtkowski
|
||||
- 22.11 -- Alex Buckley & Aleisha Amohia
|
||||
|
||||
## Credits
|
||||
|
||||
|
||||
|
||||
We thank the following individuals who contributed patches to Koha 24.11.15
|
||||
<div style="column-count: 2;">
|
||||
|
||||
- David Cook (3)
|
||||
- Jonathan Druart (4)
|
||||
- Lucas Gass (1)
|
||||
- Jacob O'Mara (3)
|
||||
- Martin Renvoize (4)
|
||||
- Marcel de Rooy (1)
|
||||
</div>
|
||||
|
||||
We thank the following libraries, companies, and other institutions who contributed
|
||||
patches to Koha 24.11.15
|
||||
<div style="column-count: 2;">
|
||||
|
||||
- [ByWater Solutions](https://bywatersolutions.com) (1)
|
||||
- Koha Community Developers (4)
|
||||
- [OpenFifth](https://openfifth.co.uk) (7)
|
||||
- [Prosentient Systems](https://www.prosentient.com.au) (3)
|
||||
- Rijksmuseum, Netherlands (1)
|
||||
</div>
|
||||
|
||||
We also especially thank the following individuals who tested patches
|
||||
for Koha
|
||||
<div style="column-count: 2;">
|
||||
|
||||
- Nick Clemens (1)
|
||||
- David Cook (3)
|
||||
- Jonathan Druart (1)
|
||||
- Andrew Fuerste-Henry (3)
|
||||
- Lucas Gass (1)
|
||||
- Brendan Lawlor (1)
|
||||
- David Nind (1)
|
||||
- Jacob O'Mara (13)
|
||||
- Phil Ringnalda (2)
|
||||
- Marcel de Rooy (2)
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
We regret any omissions. If a contributor has been inadvertently missed,
|
||||
please send a patch against these release notes to koha-devel@lists.koha-community.org.
|
||||
|
||||
## Revision control notes
|
||||
|
||||
The Koha project uses Git for version control. The current development
|
||||
version of Koha can be retrieved by checking out the main branch of:
|
||||
|
||||
- [Koha Git Repository](https://git.koha-community.org/koha-community/koha)
|
||||
|
||||
The branch for this version of Koha and future bugfixes in this release
|
||||
line is 24.11.x-security.
|
||||
|
||||
## Bugs and feature requests
|
||||
|
||||
Bug reports and feature requests can be filed at the Koha bug
|
||||
tracker at:
|
||||
|
||||
- [Koha Bugzilla](https://bugs.koha-community.org)
|
||||
|
||||
He rau ringa e oti ai.
|
||||
(Many hands finish the work)
|
||||
|
||||
Autogenerated release notes updated last on 22 Apr 2026 19:35:08.
|
||||
|
|
@ -18,7 +18,8 @@
|
|||
# along with Koha; if not, see <http://www.gnu.org/licenses>.
|
||||
|
||||
use Modern::Perl;
|
||||
use Test::More tests => 3;
|
||||
use Test::NoWarnings;
|
||||
use Test::More tests => 4;
|
||||
|
||||
use utf8;
|
||||
|
||||
|
|
@ -58,3 +59,24 @@ subtest 'Plugin related tests' => sub {
|
|||
"Processing template toolkit with a Koha plugin works"
|
||||
);
|
||||
};
|
||||
|
||||
subtest 'Security-related tests' => sub {
|
||||
plan tests => 2;
|
||||
|
||||
is(
|
||||
Koha::TemplateUtils::process_tt(
|
||||
q{[% USE dir = Directory('/') ~%]
|
||||
[% FOREACH entry IN dir.list ~%]
|
||||
<p>[% entry.abs %]</p>
|
||||
[% END %]},
|
||||
),
|
||||
q{},
|
||||
"Plugins not allowed for User-entered TT"
|
||||
);
|
||||
|
||||
is(
|
||||
Koha::TemplateUtils::process_tt(q{[% USE raw %][% 'foo' | $raw %]}),
|
||||
q{foo},
|
||||
"Koha plugins are still available"
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -54,10 +54,10 @@ describe("loads the manage MARC import page", () => {
|
|||
cy.get('select[name="format"]').should("have.value", "MARCXML");
|
||||
|
||||
//select some new options
|
||||
cy.get("#matcher").select("3", { force: true });
|
||||
cy.get("#matcher")
|
||||
.select("3", { force: true })
|
||||
.should("have.value", "3");
|
||||
|
||||
cy.get("#overlay_action")
|
||||
.select("create_new", { force: true })
|
||||
.should("have.value", "create_new");
|
||||
|
|
@ -68,11 +68,19 @@ describe("loads the manage MARC import page", () => {
|
|||
.select("ignore", { force: true })
|
||||
.should("have.value", "ignore");
|
||||
|
||||
cy.intercept("GET", "/api/v1/jobs/*").as("jobPoll");
|
||||
cy.get("#mainformsubmit").click();
|
||||
|
||||
cy.get("#job_callback").should("exist");
|
||||
const waitForJobFinished = () => {
|
||||
cy.wait("@jobPoll").then(interception => {
|
||||
if (interception.response?.body?.status !== "finished") {
|
||||
waitForJobFinished();
|
||||
}
|
||||
});
|
||||
};
|
||||
waitForJobFinished();
|
||||
|
||||
cy.contains("View batch").click();
|
||||
cy.get("#job_callback").contains("View batch").click();
|
||||
|
||||
// Now verify all values are retained
|
||||
cy.get("#new_matcher_id").should("have.value", "3");
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@
|
|||
|
||||
use Modern::Perl;
|
||||
|
||||
use Test::More tests => 38;
|
||||
use Test::More tests => 40;
|
||||
use Test::NoWarnings;
|
||||
use Test::Exception;
|
||||
use Test::Warn;
|
||||
use Time::Fake;
|
||||
|
|
@ -369,7 +370,7 @@ subtest 'is_active' => sub {
|
|||
|
||||
subtest 'add_guarantor() tests' => sub {
|
||||
|
||||
plan tests => 6;
|
||||
plan tests => 7;
|
||||
|
||||
$schema->storage->txn_begin;
|
||||
|
||||
|
|
@ -398,15 +399,16 @@ subtest 'add_guarantor() tests' => sub {
|
|||
|
||||
is( $guarantors->count, 1, 'No guarantors added' );
|
||||
|
||||
{
|
||||
local *STDERR;
|
||||
open STDERR, '>', '/dev/null';
|
||||
throws_ok
|
||||
{ $patron_1->add_guarantor({ guarantor_id => $patron_2->borrowernumber, relationship => 'father2' }); }
|
||||
warning_like(
|
||||
sub {
|
||||
throws_ok {
|
||||
$patron_1->add_guarantor( { guarantor_id => $patron_2->borrowernumber, relationship => 'father2' } );
|
||||
}
|
||||
'Koha::Exceptions::Patron::Relationship::DuplicateRelationship',
|
||||
'Exception is thrown for duplicated relationship';
|
||||
close STDERR;
|
||||
}
|
||||
'Exception is thrown for duplicated relationship';
|
||||
},
|
||||
qr{Duplicate entry.* for key '(borrower_relationships\.)?guarantor_guarantee_idx'}
|
||||
);
|
||||
|
||||
$schema->storage->txn_rollback;
|
||||
};
|
||||
|
|
@ -2962,3 +2964,99 @@ subtest 'preferred_name' => sub {
|
|||
is( $patron->preferred_name, "Preferred again", "Preferred name set on update when passed" );
|
||||
|
||||
};
|
||||
|
||||
subtest 'fixup_cardnumber and autoMemberNumValue counter' => sub {
|
||||
plan tests => 10;
|
||||
|
||||
$schema->storage->txn_begin;
|
||||
|
||||
t::lib::Mocks::mock_preference( 'autoMemberNum', 1 );
|
||||
t::lib::Mocks::mock_preference( 'ChildNeedsGuarantor', 0 );
|
||||
|
||||
my $pref_rs = $schema->resultset('Systempreference');
|
||||
|
||||
my $set_counter = sub {
|
||||
my $value = shift;
|
||||
my $row = $pref_rs->find('autoMemberNumValue');
|
||||
if ($row) { $row->update( { value => $value } ) }
|
||||
else { $pref_rs->create( { variable => 'autoMemberNumValue', value => $value } ) }
|
||||
};
|
||||
my $get_counter = sub {
|
||||
my $row = $pref_rs->find('autoMemberNumValue');
|
||||
return $row ? $row->value : undef;
|
||||
};
|
||||
|
||||
my $category = $builder->build_object( { class => 'Koha::Patron::Categories' } );
|
||||
my $library = $builder->build_object( { class => 'Koha::Libraries' } );
|
||||
|
||||
my $new_patron = sub {
|
||||
return Koha::Patron->new(
|
||||
{
|
||||
surname => 'fixup-test',
|
||||
categorycode => $category->categorycode,
|
||||
branchcode => $library->branchcode,
|
||||
cardnumber => undef,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
# Anchor well above any existing fixture cardnumbers for deterministic assertions.
|
||||
my $baseline = Koha::Patrons->search(
|
||||
{ cardnumber => { -regexp => '^-?[0-9]+$' } },
|
||||
{
|
||||
select => \'CAST(cardnumber AS SIGNED)',
|
||||
as => ['m'],
|
||||
}
|
||||
)->_resultset->get_column('m')->max
|
||||
|| 0;
|
||||
my $start = $baseline + 1_000;
|
||||
$set_counter->($start);
|
||||
|
||||
my $p1 = $new_patron->()->store;
|
||||
is( $p1->cardnumber + 0, $start + 1, 'First auto-generated cardnumber is counter + 1' );
|
||||
is( $get_counter->() + 0, $start + 1, 'Counter persisted after auto-generation' );
|
||||
|
||||
# The bug fix: renaming a patron's cardnumber must not free the old number.
|
||||
my $original = $p1->cardnumber;
|
||||
$p1->cardnumber('MANUAL-XYZ')->store;
|
||||
my $p2 = $new_patron->()->store;
|
||||
isnt( $p2->cardnumber, $original, q{Original auto-generated number not reused after rename} );
|
||||
is( $p2->cardnumber + 0, $start + 2, 'Next patron uses counter + 1, skipping the freed slot' );
|
||||
|
||||
# Deleting a patron must not free their cardnumber either.
|
||||
my $p2_cardnumber = $p2->cardnumber;
|
||||
$p2->delete;
|
||||
my $p3 = $new_patron->()->store;
|
||||
isnt( $p3->cardnumber, $p2_cardnumber, q{Deleted patron's cardnumber not reused} );
|
||||
|
||||
# Counter ahead of DB max: counter wins.
|
||||
$set_counter->( $start + 1_000_000 );
|
||||
my $p4 = $new_patron->()->store;
|
||||
is( $p4->cardnumber + 0, $start + 1_000_001, 'Counter ahead of DB max wins' );
|
||||
|
||||
# DB max ahead of counter (e.g. admin imported high numbers directly): DB max wins.
|
||||
my $high = $start + 2_000_000;
|
||||
$set_counter->(5);
|
||||
Koha::Patron->new(
|
||||
{
|
||||
surname => 'manual-high',
|
||||
categorycode => $category->categorycode,
|
||||
branchcode => $library->branchcode,
|
||||
cardnumber => "$high",
|
||||
}
|
||||
)->store;
|
||||
my $p5 = $new_patron->()->store;
|
||||
is( $p5->cardnumber + 0, $high + 1, 'DB max ahead of counter wins' );
|
||||
is( $get_counter->() + 0, $high + 1, 'Counter catches up to DB max + 1' );
|
||||
|
||||
# Pre-upgrade fallback: syspref row absent -> behaves like pre-34000 code.
|
||||
$pref_rs->find('autoMemberNumValue')->delete;
|
||||
my $p6 = $new_patron->()->store;
|
||||
is( $p6->cardnumber + 0, $high + 2, 'Legacy fallback when syspref row is absent' );
|
||||
is(
|
||||
$pref_rs->find('autoMemberNumValue'), undef,
|
||||
'Syspref row stays absent when fallback path is taken'
|
||||
);
|
||||
|
||||
$schema->storage->txn_rollback;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ subtest 'Compare sysprefs.sql with YAML files' => sub {
|
|||
@sysprefs_mod = grep !/UsageStatsID/, @sysprefs_mod; # Separate configuration page
|
||||
@sysprefs_mod = grep !/UsageStatsLastUpdateTime/, @sysprefs_mod; # Separate configuration page
|
||||
@sysprefs_mod = grep !/UsageStatsPublicID/, @sysprefs_mod; # Separate configuration page
|
||||
@sysprefs_mod = grep !/autoMemberNumValue/, @sysprefs_mod; # Internal counter, not exposed in YAML
|
||||
|
||||
my @missing_yaml = array_minus( @sysprefs_mod, @yaml_mod );
|
||||
is( scalar @missing_yaml, 0, "No system preference entries missing from sysprefs.sql" );
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ use Modern::Perl;
|
|||
use POSIX qw( ceil );
|
||||
use CGI qw ( -utf8 );
|
||||
use CGI::Cookie; # need to check cookies before having CGI parse the POST request
|
||||
use URI::Escape qw( uri_escape_utf8 uri_unescape );
|
||||
use C4::Auth qw( check_cookie_auth get_template_and_user );
|
||||
use JSON qw(encode_json);
|
||||
use C4::Auth qw( check_cookie_auth get_template_and_user );
|
||||
use C4::Context;
|
||||
use C4::Output qw( output_with_http_headers is_ajax pagination_bar output_html_with_http_headers );
|
||||
use C4::Tags qw(
|
||||
|
|
@ -38,13 +38,15 @@ use C4::Tags qw(
|
|||
my $script_name = "/cgi-bin/koha/tags/review.pl";
|
||||
my $needed_flags = { tools => 'moderate_tags' }; # FIXME: replace when more specific permission is created.
|
||||
|
||||
sub ajax_auth_cgi { # returns CGI object
|
||||
my $needed_flags = shift;
|
||||
my %cookies = CGI::Cookie->fetch;
|
||||
my $input = CGI->new;
|
||||
my $sessid = $cookies{'CGISESSID'}->value;
|
||||
my ($auth_status) = check_cookie_auth($sessid, $needed_flags);
|
||||
if ($auth_status ne "ok") {
|
||||
sub ajax_auth_cgi { # returns CGI object
|
||||
my $needed_flags = shift;
|
||||
my %cookies = CGI::Cookie->fetch;
|
||||
my $input = CGI->new;
|
||||
my $sessid = $cookies{'CGISESSID'}->value;
|
||||
my ($auth_status) = check_cookie_auth( $sessid, $needed_flags );
|
||||
if ( $auth_status ne "ok" ) {
|
||||
|
||||
#FIXME: This should return a HTTP error and not a script
|
||||
output_with_http_headers $input, undef,
|
||||
"window.alert('Your CGI session cookie ($sessid) is not current. " .
|
||||
"Please refresh the page and try again.');\n", 'js';
|
||||
|
|
@ -53,24 +55,25 @@ sub ajax_auth_cgi { # returns CGI object
|
|||
return $input;
|
||||
}
|
||||
|
||||
if (is_ajax()) {
|
||||
my $input = &ajax_auth_cgi($needed_flags);
|
||||
my $operator = C4::Context->userenv->{'number'}; # must occur AFTER auth
|
||||
my $js_reply;
|
||||
my $op = $input->param('op') || q{};
|
||||
my $tag = $input->param('tag');
|
||||
if ( is_ajax() ) {
|
||||
my $input = &ajax_auth_cgi($needed_flags);
|
||||
my $operator = C4::Context->userenv->{'number'}; # must occur AFTER auth
|
||||
my $op = $input->param('op') || q{};
|
||||
my $tag = $input->param('tag');
|
||||
my $status;
|
||||
if ( $op eq 'test' ) {
|
||||
$tag = uri_unescape($tag);
|
||||
my $check = is_approved($tag);
|
||||
$js_reply = ( $check >= 1 ? 'success' : $check <= -1 ? 'failure' : 'indeterminate' ) . "_test('".uri_escape_utf8($tag)."');\n";
|
||||
$status = $check >= 1 ? 'success' : $check <= -1 ? 'failure' : 'indeterminate';
|
||||
} elsif ( $op eq 'cud-approve' ) {
|
||||
$status = whitelist( $operator, $tag ) ? 'success' : 'failure';
|
||||
} elsif ( $op eq 'cud-reject' ) {
|
||||
$status = blacklist( $operator, $tag ) ? 'success' : 'failure';
|
||||
}
|
||||
elsif ($op eq 'cud-approve') {
|
||||
$js_reply = ( whitelist($operator,$tag) ? 'success' : 'failure') . "_approve('".uri_escape_utf8($tag)."');\n";
|
||||
}
|
||||
elsif ($op eq 'cud-reject') {
|
||||
$js_reply = ( blacklist($operator,$tag) ? 'success' : 'failure') . "_reject('".uri_escape_utf8($tag)."');\n";
|
||||
}
|
||||
output_with_http_headers $input, undef, $js_reply, 'js';
|
||||
my $response = {
|
||||
status => $status,
|
||||
tag => $tag,
|
||||
};
|
||||
output_with_http_headers $input, undef, encode_json($response), 'json';
|
||||
exit;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue