From 6c303f3c1cdc3a9fd6b133716bcd11440f839f8b Mon Sep 17 00:00:00 2001 From: Wainui Witika-Park Date: Wed, 27 Mar 2024 01:03:49 +0000 Subject: [PATCH 01/56] Bug 34893: [22.05] (follow-up) change number of tests --- t/db_dependent/ILSDI_Services.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/db_dependent/ILSDI_Services.t b/t/db_dependent/ILSDI_Services.t index cf0080b3cc..14580c4258 100755 --- a/t/db_dependent/ILSDI_Services.t +++ b/t/db_dependent/ILSDI_Services.t @@ -19,7 +19,7 @@ use Modern::Perl; use CGI qw ( -utf8 ); -use Test::More tests => 12; +use Test::More tests => 13; use Test::MockModule; use t::lib::Mocks; use t::lib::TestBuilder; From a4460bb5e08b0635683fe16e77c5e4e9a9648faa Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Tue, 5 Jan 2021 11:18:26 +0100 Subject: [PATCH 02/56] Bug 27342: Improve test for OPAC We don't need to build allowed_scripts_for_private_opac for staff Signed-off-by: Martin Renvoize --- C4/Auth.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/C4/Auth.pm b/C4/Auth.pm index 6ce57fe54f..2c34375f97 100644 --- a/C4/Auth.pm +++ b/C4/Auth.pm @@ -827,7 +827,7 @@ sub checkauth { my $template_name = shift; $type = 'opac' unless $type; - unless ( C4::Context->preference("OpacPublic") ) { + if ( $type eq 'opac' && !C4::Context->preference("OpacPublic") ) { my @allowed_scripts_for_private_opac = qw( opac-memberentry.tt opac-registration-email-sent.tt From 25cd8e9239524f3d36820c8cbb42456376647038 Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Tue, 5 Jan 2021 11:28:16 +0100 Subject: [PATCH 03/56] Bug 27342: Remove dbh from C4::Auth We must not pass $dbh but retrieve it when needed instead Signed-off-by: Martin Renvoize --- C4/Auth.pm | 33 ++++++++++++++++---------------- C4/Auth_with_cas.pm | 6 +++--- C4/Auth_with_ldap.pm | 4 ++-- C4/SIP/ILS/Patron.pm | 3 +-- Koha/REST/V1/Auth.pm | 3 +-- Koha/REST/V1/Patrons/Password.pm | 3 +-- opac/sco/sco-main.pl | 3 +-- t/db_dependent/Auth.t | 23 +++++++++++----------- t/db_dependent/Auth_with_ldap.t | 25 +++++++++++------------- t/db_dependent/Log.t | 23 ++++++++++------------ 10 files changed, 57 insertions(+), 69 deletions(-) diff --git a/C4/Auth.pm b/C4/Auth.pm index 2c34375f97..1264ef8c1d 100644 --- a/C4/Auth.pm +++ b/C4/Auth.pm @@ -406,7 +406,6 @@ sub get_template_and_user { # we add them to the logged-in search history my @recentSearches = C4::Search::History::get_from_session( { cgi => $in->{'query'} } ); if (@recentSearches) { - my $dbh = C4::Context->dbh; my $query = q{ INSERT INTO search_history(userid, sessionid, query_desc, query_cgi, type, total, time ) VALUES (?, ?, ?, ?, ?, ?, ?) @@ -840,7 +839,6 @@ sub checkauth { @allowed_scripts_for_private_opac; } - my $dbh = C4::Context->dbh; my $timeout = _timeout_syspref(); my $cookie_mgr = Koha::CookieManager->new; @@ -1050,7 +1048,7 @@ sub checkauth { my $retuserid; # Do not pass password here, else shib will not be checked in checkpw. - ( $return, $cardnumber, $retuserid ) = checkpw( $dbh, $q_userid, undef, $query ); + ( $return, $cardnumber, $retuserid ) = checkpw( $q_userid, undef, $query ); $userid = $retuserid; $shibSuccess = $return; $info{'invalidShibLogin'} = 1 unless ($return); @@ -1061,7 +1059,7 @@ sub checkauth { if ( $cas && $query->param('ticket') ) { my $retuserid; ( $return, $cardnumber, $retuserid, $cas_ticket ) = - checkpw( $dbh, $userid, $password, $query, $type ); + checkpw( $userid, $password, $query, $type ); $userid = $retuserid; $info{'invalidCasLogin'} = 1 unless ($return); } @@ -1130,7 +1128,7 @@ sub checkauth { { ( $return, $cardnumber, $retuserid, $cas_ticket ) = - checkpw( $dbh, $q_userid, $password, $query, $type ); + checkpw( $q_userid, $password, $query, $type ); $userid = $retuserid if ($retuserid); $info{'invalid_username_or_password'} = 1 unless ($return); } @@ -1180,6 +1178,7 @@ sub checkauth { FROM borrowers LEFT JOIN branches on borrowers.branchcode=branches.branchcode "; + my $dbh = C4::Context->dbh; my $sth = $dbh->prepare("$select where userid=?"); $sth->execute($userid); unless ( $sth->rows ) { @@ -1544,7 +1543,6 @@ sub check_api_auth { my $query = shift; my $flagsrequired = shift; - my $dbh = C4::Context->dbh; my $timeout = _timeout_syspref(); unless ( C4::Context->preference('Version') ) { @@ -1597,7 +1595,7 @@ sub check_api_auth { # In case of a CAS authentication, we use the ticket instead of the password my $PT = $query->param('PT'); - ( $return, $cardnumber, $userid, $cas_ticket ) = check_api_auth_cas( $dbh, $PT, $query ); # EXTERNAL AUTH + ( $return, $cardnumber, $userid, $cas_ticket ) = check_api_auth_cas( $PT, $query ); # EXTERNAL AUTH } else { # User / password auth @@ -1607,7 +1605,7 @@ sub check_api_auth { return ( "failed", undef, undef ); } my $newuserid; - ( $return, $cardnumber, $newuserid, $cas_ticket ) = checkpw( $dbh, $userid, $password, $query ); + ( $return, $cardnumber, $newuserid, $cas_ticket ) = checkpw( $userid, $password, $query ); } if ( $return and haspermission( $userid, $flagsrequired ) ) { @@ -1629,6 +1627,7 @@ sub check_api_auth { $userflags, $branchcode, $branchname, $emailaddress ); + my $dbh = C4::Context->dbh; my $sth = $dbh->prepare( "select borrowernumber, firstname, surname, flags, borrowers.branchcode, branches.branchname as branchname, email from borrowers left join branches on borrowers.branchcode=branches.branchcode where userid=?" @@ -1894,7 +1893,7 @@ sub get_session { # Currently it's only passed from C4::SIP::ILS::Patron::check_password, but # not having a userenv defined could cause a crash. sub checkpw { - my ( $dbh, $userid, $password, $query, $type, $no_set_userenv ) = @_; + my ( $userid, $password, $query, $type, $no_set_userenv ) = @_; $type = 'opac' unless $type; # Get shibboleth login attribute @@ -1931,10 +1930,9 @@ sub checkpw { # In case of a CAS authentication, we use the ticket instead of the password my $ticket = $query->param('ticket'); - $query->delete('ticket'); # remove ticket to come back to original URL - my ( $retval, $retcard, $retuserid, $cas_ticket, $patron ) = - checkpw_cas( $ticket, $query, $type ); # EXTERNAL AUTH - if ($retval) { + $query->delete('ticket'); # remove ticket to come back to original URL + my ( $retval, $retcard, $retuserid, $cas_ticket, $patron ) = checkpw_cas( $ticket, $query, $type ); # EXTERNAL AUTH + if ( $retval ) { @return = ( $retval, $retcard, $retuserid, $patron, $cas_ticket ); } else { @return = (0); @@ -1965,10 +1963,10 @@ sub checkpw { } # INTERNAL AUTH - if ($check_internal_as_fallback) { - @return = checkpw_internal( $dbh, $userid, $password, $no_set_userenv ); + if ( $check_internal_as_fallback ) { + @return = checkpw_internal( $userid, $password, $no_set_userenv); push( @return, $patron ); - $passwd_ok = 1 if $return[0] > 0; # 1 or 2 + $passwd_ok = 1 if $return[0] > 0; # 1 or 2 } if ($patron) { @@ -1993,11 +1991,12 @@ sub checkpw { } sub checkpw_internal { - my ( $dbh, $userid, $password, $no_set_userenv ) = @_; + my ( $userid, $password, $no_set_userenv ) = @_; $password = Encode::encode( 'UTF-8', $password ) if Encode::is_utf8($password); + my $dbh = C4::Context->dbh; my $sth = $dbh->prepare( "select password,cardnumber,borrowernumber,userid,firstname,surname,borrowers.branchcode,branches.branchname,flags from borrowers join branches on borrowers.branchcode=branches.branchcode where userid=?" diff --git a/C4/Auth_with_cas.pm b/C4/Auth_with_cas.pm index 753771cdee..c50e9c99dc 100644 --- a/C4/Auth_with_cas.pm +++ b/C4/Auth_with_cas.pm @@ -99,7 +99,7 @@ sub login_cas_url { # Checks for password correctness # In our case : is there a ticket, is it valid and does it match one of our users ? sub checkpw_cas { - my ($dbh, $ticket, $query, $type) = @_; + my ($ticket, $query, $type) = @_; my $retnumber; my ( $cas, $uri ) = _get_cas_and_service($query, undef, $type); @@ -117,7 +117,6 @@ sub checkpw_cas { # we should store the CAS ticekt too, we need this for single logout https://apereo.github.io/cas/4.2.x/protocol/CAS-Protocol-Specification.html#233-single-logout # Does it match one of our users ? - my $dbh = C4::Context->dbh; my $patron = Koha::Patrons->find( { userid => $userid } ); if ($patron) { return ( 1, $patron->cardnumber, $patron->userid, $ticket, $patron ); @@ -144,7 +143,7 @@ sub checkpw_cas { # Proxy CAS auth sub check_api_auth_cas { - my ($dbh, $PT, $query, $type) = @_; + my ($PT, $query, $type) = @_; my $retnumber; my ( $cas, $uri ) = _get_cas_and_service($query, undef, $type); @@ -161,6 +160,7 @@ sub check_api_auth_cas { # we should store the CAS ticket too, we need this for single logout https://apereo.github.io/cas/4.2.x/protocol/CAS-Protocol-Specification.html#233-single-logout # Does it match one of our users ? + my $dbh = C4::Context->dbh; my $sth = $dbh->prepare("select cardnumber from borrowers where userid=?"); $sth->execute($userid); if ( $sth->rows ) { diff --git a/C4/Auth_with_ldap.pm b/C4/Auth_with_ldap.pm index a7ffe5271b..3a4de52618 100644 --- a/C4/Auth_with_ldap.pm +++ b/C4/Auth_with_ldap.pm @@ -109,7 +109,7 @@ sub search_method { } sub checkpw_ldap { - my ($dbh, $userid, $password) = @_; + my ($userid, $password) = @_; my @hosts = split(',', $prefhost); my $db = Net::LDAP->new(\@hosts); unless ( $db ) { @@ -356,7 +356,7 @@ sub _do_changepassword { #warn "changing local password for borrowernumber=$borrowerid to '$digest'\n"; Koha::Patrons->find($borrowerid)->set_password({ password => $password, skip_validation => 1 }); - my ($ok, $cardnum) = checkpw_internal(C4::Context->dbh, $userid, $password); + my ($ok, $cardnum) = checkpw_internal($userid, $password); return $cardnum if $ok; warn "Password mismatch after update to borrowernumber=$borrowerid"; diff --git a/C4/SIP/ILS/Patron.pm b/C4/SIP/ILS/Patron.pm index fd8e92c617..e5542bfb2b 100644 --- a/C4/SIP/ILS/Patron.pm +++ b/C4/SIP/ILS/Patron.pm @@ -281,9 +281,8 @@ sub check_password { # If the record has a NULL password, accept '' as match return $pwd eq q{} unless $self->{password}; - my $dbh = C4::Context->dbh; my $ret = 0; - ($ret) = checkpw( $dbh, $self->{userid}, $pwd, undef, undef, 1 ); # dbh, userid, query, type, no_set_userenv + ($ret) = checkpw( $self->{userid}, $pwd, undef, undef, 1 ); # userid, query, type, no_set_userenv return $ret; } diff --git a/Koha/REST/V1/Auth.pm b/Koha/REST/V1/Auth.pm index 182db518f6..7f99effbda 100644 --- a/Koha/REST/V1/Auth.pm +++ b/Koha/REST/V1/Auth.pm @@ -486,8 +486,7 @@ sub _basic_auth { my $decoded_credentials = decode_base64( $credentials ); my ( $user_id, $password ) = split( /:/, $decoded_credentials, 2 ); - my $dbh = C4::Context->dbh; - unless ( checkpw_internal($dbh, $user_id, $password ) ) { + unless ( checkpw_internal($user_id, $password ) ) { Koha::Exceptions::Authorization::Unauthorized->throw( error => 'Invalid password' ); } diff --git a/Koha/REST/V1/Patrons/Password.pm b/Koha/REST/V1/Patrons/Password.pm index 35379edf18..96f259c381 100644 --- a/Koha/REST/V1/Patrons/Password.pm +++ b/Koha/REST/V1/Patrons/Password.pm @@ -119,8 +119,7 @@ sub set_public { } return try { - my $dbh = C4::Context->dbh; - unless ( checkpw_internal($dbh, $user->userid, $old_password ) ) { + unless ( checkpw_internal($user->userid, $old_password ) ) { return $c->render( status => 400, openapi => { error => "Invalid password" } diff --git a/opac/sco/sco-main.pl b/opac/sco/sco-main.pl index a89f2538d6..ac89db749c 100755 --- a/opac/sco/sco-main.pl +++ b/opac/sco/sco-main.pl @@ -118,8 +118,7 @@ my $issuer = Koha::Patrons->find( $issuerid )->unblessed; my $patronid = $jwt ? Koha::Token->new->decode_jwt({ token => $jwt }) : undef; unless ( $patronid ) { if ( C4::Context->preference('SelfCheckoutByLogin') ) { - my $dbh = C4::Context->dbh; - ( undef, $patronid ) = checkpw( $dbh, $patronlogin, $patronpw ); + ( undef, $patronid ) = checkpw( $patronlogin, $patronpw ); } else { # People should not do that unless they know what they are doing! # SelfCheckAllowByIPRanges MUST be configured diff --git a/t/db_dependent/Auth.t b/t/db_dependent/Auth.t index a7bc1c885e..ef9e445ad8 100755 --- a/t/db_dependent/Auth.t +++ b/t/db_dependent/Auth.t @@ -28,7 +28,6 @@ BEGIN { my $schema = Koha::Database->schema; my $builder = t::lib::TestBuilder->new; -my $dbh = C4::Context->dbh; # FIXME: SessionStorage defaults to mysql, but it seems to break transaction # handling @@ -411,14 +410,14 @@ subtest 'no_set_userenv parameter tests' => sub { t::lib::Mocks::mock_preference( 'RequireStrongPassword', 0 ); $patron->set_password({ password => $password }); - ok( checkpw( $dbh, $patron->userid, $password, undef, undef, 1 ), 'checkpw returns true' ); + ok( checkpw( $patron->userid, $password, undef, undef, 1 ), 'checkpw returns true' ); is( C4::Context->userenv, undef, 'Userenv should be undef as required' ); C4::Context->_new_userenv('DUMMY SESSION'); C4::Context->set_userenv(0,0,0,'firstname','surname', $library->branchcode, 'Library 1', 0, '', ''); is( C4::Context->userenv->{branch}, $library->branchcode, 'Userenv gives correct branch' ); - ok( checkpw( $dbh, $patron->userid, $password, undef, undef, 1 ), 'checkpw returns true' ); + ok( checkpw( $patron->userid, $password, undef, undef, 1 ), 'checkpw returns true' ); is( C4::Context->userenv->{branch}, $library->branchcode, 'Userenv branch is preserved if no_set_userenv is true' ); - ok( checkpw( $dbh, $patron->userid, $password, undef, undef, 0 ), 'checkpw still returns true' ); + ok( checkpw( $patron->userid, $password, undef, undef, 0 ), 'checkpw still returns true' ); isnt( C4::Context->userenv->{branch}, $library->branchcode, 'Userenv branch is overwritten if no_set_userenv is false' ); }; @@ -433,15 +432,15 @@ subtest 'checkpw lockout tests' => sub { t::lib::Mocks::mock_preference( 'FailedLoginAttempts', 1 ); $patron->set_password({ password => $password }); - my ( $checkpw, undef, undef ) = checkpw( $dbh, $patron->cardnumber, $password, undef, undef, 1 ); + my ( $checkpw, undef, undef ) = checkpw( $patron->cardnumber, $password, undef, undef, 1 ); ok( $checkpw, 'checkpw returns true with right password when logging in via cardnumber' ); - ( $checkpw, undef, undef ) = checkpw( $dbh, $patron->userid, "wrong_password", undef, undef, 1 ); + ( $checkpw, undef, undef ) = checkpw( $patron->userid, "wrong_password", undef, undef, 1 ); is( $checkpw, 0, 'checkpw returns false when given wrong password' ); $patron = $patron->get_from_storage; is( $patron->account_locked, 1, "Account is locked from failed login"); - ( $checkpw, undef, undef ) = checkpw( $dbh, $patron->userid, $password, undef, undef, 1 ); + ( $checkpw, undef, undef ) = checkpw( $patron->userid, $password, undef, undef, 1 ); is( $checkpw, undef, 'checkpw returns undef with right password when account locked' ); - ( $checkpw, undef, undef ) = checkpw( $dbh, $patron->cardnumber, $password, undef, undef, 1 ); + ( $checkpw, undef, undef ) = checkpw( $patron->cardnumber, $password, undef, undef, 1 ); is( $checkpw, undef, 'checkpw returns undefwith right password when logging in via cardnumber if account locked' ); }; @@ -642,7 +641,7 @@ subtest 'Check value of login_attempts in checkpw' => sub { $patron->password('123')->store; # yes, deliberately not hashed is( $patron->account_locked, 0, 'Patron not locked' ); - my @test = checkpw( $dbh, $patron->userid, '123', undef, 'opac', 1 ); + my @test = checkpw( $patron->userid, '123', undef, 'opac', 1 ); # Note: 123 will not be hashed to 123 ! is( $test[0], 0, 'checkpw should have failed' ); $patron->discard_changes; # refresh @@ -650,7 +649,7 @@ subtest 'Check value of login_attempts in checkpw' => sub { is( $patron->account_locked, 1, 'Check locked status' ); # And another try to go over the limit: different return value! - @test = checkpw( $dbh, $patron->userid, '123', undef, 'opac', 1 ); + @test = checkpw( $patron->userid, '123', undef, 'opac', 1 ); is( @test, 0, 'checkpw failed again and returns nothing now' ); $patron->discard_changes; # refresh is( $patron->login_attempts, 3, 'Login attempts not increased anymore' ); @@ -660,11 +659,11 @@ subtest 'Check value of login_attempts in checkpw' => sub { my $auth = Test::MockModule->new( 'C4::Auth' ); $auth->mock( 'checkpw_hash', sub { return 1; } ); # not for production :) $patron->login_attempts(0)->store; - @test = checkpw( $dbh, $patron->userid, '123', undef, 'opac', 1 ); + @test = checkpw( $patron->userid, '123', undef, 'opac', 1 ); is( $test[0], 1, 'Build confidence in the mock' ); $patron->login_attempts(-1)->store; is( $patron->account_locked, 1, 'Check administrative lockout' ); - @test = checkpw( $dbh, $patron->userid, '123', undef, 'opac', 1 ); + @test = checkpw( $patron->userid, '123', undef, 'opac', 1 ); is( @test, 0, 'checkpw gave red' ); $patron->discard_changes; # refresh is( $patron->login_attempts, -1, 'Still locked out' ); diff --git a/t/db_dependent/Auth_with_ldap.t b/t/db_dependent/Auth_with_ldap.t index 39f6e8ef02..df385e1569 100755 --- a/t/db_dependent/Auth_with_ldap.t +++ b/t/db_dependent/Auth_with_ldap.t @@ -28,8 +28,6 @@ use C4::Context; use Koha::Patrons; -my $dbh = ''; - # Start transaction my $schema = Koha::Database->new->schema; $schema->storage->txn_begin(); @@ -131,12 +129,11 @@ subtest 'checkpw_ldap tests' => sub { plan tests => 4; - my $dbh = C4::Context->dbh; ## Connection fail tests $desired_connection_result = 'error'; warning_is { $ret = - C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', password => 'hey' ); + C4::Auth_with_ldap::checkpw_ldap( 'hola', password => 'hey' ); } 'LDAP connexion failed', 'checkpw_ldap prints correct warning if LDAP conexion fails'; @@ -158,7 +155,7 @@ subtest 'checkpw_ldap tests' => sub { reload_ldap_module(); warning_like { - $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', + $ret = C4::Auth_with_ldap::checkpw_ldap( 'hola', password => 'hey' ); } qr/Anonymous LDAP bind failed: LDAP error #1: error_name/, @@ -171,7 +168,7 @@ subtest 'checkpw_ldap tests' => sub { reload_ldap_module(); warning_like { - $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', + $ret = C4::Auth_with_ldap::checkpw_ldap( 'hola', password => 'hey' ); } qr/LDAP bind failed as kohauser hola: LDAP error #1: error_name/, @@ -204,7 +201,7 @@ subtest 'checkpw_ldap tests' => sub { } ); - C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', password => 'hey' ); + C4::Auth_with_ldap::checkpw_ldap( 'hola', password => 'hey' ); ok( Koha::Patrons->find($borrower->{borrowernumber})->extended_attributes->count, 'Extended attributes are not deleted' @@ -219,7 +216,7 @@ subtest 'checkpw_ldap tests' => sub { $patron->delete; reload_ldap_module(); is( - C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', password => 'hey' ), + C4::Auth_with_ldap::checkpw_ldap( 'hola', password => 'hey' ), 0, 'checkpw_ldap returns 0 if user lookup returns 0' ); @@ -228,7 +225,7 @@ subtest 'checkpw_ldap tests' => sub { reload_ldap_module(); warning_like { - $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', + $ret = C4::Auth_with_ldap::checkpw_ldap( 'hola', password => 'hey' ); } qr/LDAP bind failed as kohauser hola: LDAP error #1: error_name/, @@ -246,7 +243,7 @@ subtest 'checkpw_ldap tests' => sub { reload_ldap_module(); warning_like { - $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', + $ret = C4::Auth_with_ldap::checkpw_ldap( 'hola', password => 'hey' ); } qr/LDAP bind failed as kohauser hola: LDAP error #1: error_name/, @@ -271,7 +268,7 @@ subtest 'checkpw_ldap tests' => sub { reload_ldap_module(); warning_like { - $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', + $ret = C4::Auth_with_ldap::checkpw_ldap( 'hola', password => 'hey' ); } qr/LDAP bind failed as ldapuser cn=Manager,dc=metavore,dc=com: LDAP error #1: error_name/, @@ -286,7 +283,7 @@ qr/LDAP bind failed as ldapuser cn=Manager,dc=metavore,dc=com: LDAP error #1: er reload_ldap_module(); warning_like { - $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', + $ret = C4::Auth_with_ldap::checkpw_ldap( 'hola', password => 'hey' ); } qr/LDAP Auth rejected : invalid password for user 'hola'./, @@ -300,7 +297,7 @@ qr/LDAP Auth rejected : invalid password for user 'hola'./, reload_ldap_module(); warning_like { - $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', + $ret = C4::Auth_with_ldap::checkpw_ldap( 'hola', password => 'hey' ); } qr/LDAP bind failed as ldapuser cn=Manager,dc=metavore,dc=com: LDAP error #1: error_name/, @@ -313,7 +310,7 @@ qr/LDAP bind failed as ldapuser cn=Manager,dc=metavore,dc=com: LDAP error #1: er reload_ldap_module(); warning_like { - $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', + $ret = C4::Auth_with_ldap::checkpw_ldap( 'hola', password => 'hey' ); } qr/LDAP Auth rejected : invalid password for user 'hola'./, diff --git a/t/db_dependent/Log.t b/t/db_dependent/Log.t index 0e46eea4c9..fd821252d3 100755 --- a/t/db_dependent/Log.t +++ b/t/db_dependent/Log.t @@ -30,7 +30,6 @@ use t::lib::TestBuilder; # Make sure we can rollback. our $schema = Koha::Database->new->schema; $schema->storage->txn_begin; -our $dbh = C4::Context->dbh; subtest 'Existing tests' => sub { plan tests => 3; @@ -47,17 +46,15 @@ subtest 'Existing tests' => sub { ok($success, "logaction seemed to work"); # We want numbers to be the same between runs. - $dbh->do("DELETE FROM action_logs;"); + Koha::ActionLogs->search->delete; t::lib::Mocks::mock_preference('CronjobLog',0); cronlogaction(); - my $cronJobCount = $dbh->selectrow_array("SELECT COUNT(*) FROM action_logs WHERE module='CRONJOBS';",{}); - is($cronJobCount,0,"Cronjob not logged as expected."); + is(Koha::ActionLogs->search({ module => 'CRONJOBS' })->count,0,"Cronjob not logged as expected."); t::lib::Mocks::mock_preference('CronjobLog',1); cronlogaction(); - $cronJobCount = $dbh->selectrow_array("SELECT COUNT(*) FROM action_logs WHERE module='CRONJOBS';",{}); - is($cronJobCount,1,"Cronjob logged as expected."); + is(Koha::ActionLogs->search({ module => 'CRONJOBS' })->count,0,"Cronjob logged as expected."); }; subtest 'logaction(): interface is correctly logged' => sub { @@ -65,28 +62,28 @@ subtest 'logaction(): interface is correctly logged' => sub { plan tests => 4; # No interface passed, using C4::Context->interface - $dbh->do("DELETE FROM action_logs;"); + Koha::ActionLogs->search->delete; C4::Context->interface( 'commandline' ); logaction( "MEMBERS", "MODIFY", 1, "test operation"); my $log = Koha::ActionLogs->search->next; is( $log->interface, 'commandline', 'Interface correctly deduced (commandline)'); # No interface passed, using C4::Context->interface - $dbh->do("DELETE FROM action_logs;"); + Koha::ActionLogs->search->delete; C4::Context->interface( 'opac' ); logaction( "MEMBERS", "MODIFY", 1, "test operation"); $log = Koha::ActionLogs->search->next; is( $log->interface, 'opac', 'Interface correctly deduced (opac)'); # Explicit interfaces - $dbh->do("DELETE FROM action_logs;"); + Koha::ActionLogs->search->delete; C4::Context->interface( 'intranet' ); logaction( "MEMBERS", "MODIFY", 1, 'test info', 'intranet'); $log = Koha::ActionLogs->search->next; is( $log->interface, 'intranet', 'Passed interface is respected (intranet)'); # Explicit interfaces - $dbh->do("DELETE FROM action_logs;"); + Koha::ActionLogs->search->delete; C4::Context->interface( 'sip' ); logaction( "MEMBERS", "MODIFY", 1, 'test info', 'sip'); $log = Koha::ActionLogs->search->next; @@ -114,7 +111,7 @@ subtest 'GDPR logging' => sub { t::lib::Mocks::mock_preference('AuthFailureLog', 1); my $strong_password = 'N0tStr0ngAnyM0reN0w:)'; $patron->set_password({ password => $strong_password }); - my @ret = checkpw( $dbh, $patron->userid, 'WrongPassword', undef, undef, 1); + my @ret = checkpw( $patron->userid, 'WrongPassword', undef, undef, 1); is( $ret[0], 0, 'Authentication failed' ); # Look for auth failure but NOT on patron id, pass userid in info parameter $logs = Koha::ActionLogs->search( @@ -126,7 +123,7 @@ subtest 'GDPR logging' => sub { ); is( $logs->count, 1, 'We should find one auth failure with this userid' ); t::lib::Mocks::mock_preference('AuthFailureLog', 0); - @ret = checkpw( $dbh, $patron->userid, 'WrongPassword', undef, undef, 1); + @ret = checkpw( $patron->userid, 'WrongPassword', undef, undef, 1); $logs = Koha::ActionLogs->search( { module => 'AUTH', @@ -136,7 +133,7 @@ subtest 'GDPR logging' => sub { ); is( $logs->count, 1, 'Still only one failure with this userid' ); t::lib::Mocks::mock_preference('AuthSuccessLog', 1); - @ret = checkpw( $dbh, $patron->userid, $strong_password, undef, undef, 1); + @ret = checkpw( $patron->userid, $strong_password, undef, undef, 1); is( $ret[0], 1, 'Authentication succeeded' ); # Now we can look for patron id $logs = Koha::ActionLogs->search( From f11737f987efe148cd4dd8e6d84cee573a2e265d Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Wed, 10 Aug 2022 08:12:53 +0100 Subject: [PATCH 04/56] Bug 27342: (QA follow-up) Remove dbh from new tests --- t/db_dependent/Auth.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/db_dependent/Auth.t b/t/db_dependent/Auth.t index ef9e445ad8..a10ce20ade 100755 --- a/t/db_dependent/Auth.t +++ b/t/db_dependent/Auth.t @@ -678,11 +678,11 @@ subtest 'Check value of login_attempts in checkpw' => sub { my $patron = $builder->build_object({ class => 'Koha::Patrons' }); $patron->set_password({ password => '123', skip_validation => 1 }); - my @test = checkpw( $dbh, $patron->userid, '123', undef, 'opac', 1 ); + my @test = checkpw( $patron->userid, '123', undef, 'opac', 1 ); is( $test[0], 1, 'Patron authenticated correctly' ); $patron->password_expiration_date('2020-01-01')->store; - @test = checkpw( $dbh, $patron->userid, '123', undef, 'opac', 1 ); + @test = checkpw( $patron->userid, '123', undef, 'opac', 1 ); is( $test[0], -2, 'Patron returned as expired correctly' ); }; From e110f3cca51666a9f19d7fec3a4cbcc253f22f91 Mon Sep 17 00:00:00 2001 From: Tomas Cohen Arazi Date: Tue, 16 Aug 2022 10:50:47 -0300 Subject: [PATCH 05/56] Bug 27342: (QA follow-up) Fix test Signed-off-by: Tomas Cohen Arazi --- t/db_dependent/Log.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/db_dependent/Log.t b/t/db_dependent/Log.t index fd821252d3..cfdbab3102 100755 --- a/t/db_dependent/Log.t +++ b/t/db_dependent/Log.t @@ -54,7 +54,7 @@ subtest 'Existing tests' => sub { t::lib::Mocks::mock_preference('CronjobLog',1); cronlogaction(); - is(Koha::ActionLogs->search({ module => 'CRONJOBS' })->count,0,"Cronjob logged as expected."); + is(Koha::ActionLogs->search({ module => 'CRONJOBS' })->count,1,"Cronjob logged as expected."); }; subtest 'logaction(): interface is correctly logged' => sub { From 6a65e5ddfc8d6711082786e186199293c028b765 Mon Sep 17 00:00:00 2001 From: Tomas Cohen Arazi Date: Wed, 17 Aug 2022 10:33:07 -0300 Subject: [PATCH 06/56] Bug 27342: Fix C4::ILSDI::Services::AuthenticatePatron Signed-off-by: Tomas Cohen Arazi --- C4/ILSDI/Services.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/C4/ILSDI/Services.pm b/C4/ILSDI/Services.pm index eb5361ab84..ed23d464db 100644 --- a/C4/ILSDI/Services.pm +++ b/C4/ILSDI/Services.pm @@ -398,7 +398,7 @@ sub AuthenticatePatron { my ($cgi) = @_; my $username = $cgi->param('username'); my $password = $cgi->param('password'); - my ($status, $cardnumber, $userid, $patron) = C4::Auth::checkpw( C4::Context->dbh, $username, $password ); + my ($status, $cardnumber, $userid, $patron) = C4::Auth::checkpw( $username, $password ); if ( $status == 1 ) { # Track the login $patron->update_lastseen('connection'); From 937ff3d98451d23d8f58053acec6d305c1958df3 Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Tue, 6 Dec 2022 17:07:02 -0300 Subject: [PATCH 07/56] Bug 35343: Add record accessor method to Koha::Authority Code lifted from bug 31794 to fix already backported bug 26611. Unit tests included. Signed-off-by: Martin Renvoize (cherry picked from commit 40115a2c8cba3e081ffd0710899ef4556a3bbb54) Signed-off-by: Matt Blenkinsop Signed-off-by: Wainui Witika-Park --- Koha/Authority.pm | 45 ++++++++++++++++- t/db_dependent/Koha/Authorities.t | 81 ++++++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 3 deletions(-) diff --git a/Koha/Authority.pm b/Koha/Authority.pm index cec6c662f4..828d4c75b2 100644 --- a/Koha/Authority.pm +++ b/Koha/Authority.pm @@ -95,8 +95,7 @@ sub controlled_indicators { ? 'UNIMARCAUTH' : 'MARC21'; if( !$record ) { - $record = MARC::Record->new_from_xml( - $self->marcxml, 'UTF-8', $flavour ); + $record = $self->record; } if( !$self->{_report_tag} ) { @@ -114,6 +113,48 @@ sub controlled_indicators { }); } +=head3 get_identifiers + + my $identifiers = $author->get_identifiers; + +Return a list of identifiers of the authors which are in 024$2$a + +=cut + +sub get_identifiers { + my ( $self, $params ) = @_; + + my $record = $self->record; + + my @identifiers; + for my $field ( $record->field('024') ) { + my $sf_2 = $field->subfield('2'); + my $sf_a = $field->subfield('a'); + next unless $sf_2 && $sf_a; + push @identifiers, {source => $sf_2, number => $sf_a, }; + } + + return \@identifiers; +} + +=head3 record + + my $record = $authority->record() + +Return the MARC::Record for this authority + +=cut + +sub record { + my ( $self ) = @_; + + my $flavour = + C4::Context->preference('marcflavour') eq 'UNIMARC' + ? 'UNIMARCAUTH' + : 'MARC21'; + return MARC::Record->new_from_xml( $self->marcxml, 'UTF-8', $flavour ); +} + =head2 Class Methods =head3 type diff --git a/t/db_dependent/Koha/Authorities.t b/t/db_dependent/Koha/Authorities.t index 04ad663e28..699ee1c34a 100755 --- a/t/db_dependent/Koha/Authorities.t +++ b/t/db_dependent/Koha/Authorities.t @@ -19,7 +19,7 @@ use Modern::Perl; -use Test::More tests => 7; +use Test::More tests => 9; use MARC::Field; use MARC::File::XML; use MARC::Record; @@ -242,4 +242,83 @@ sub few_marc_records { return [ $marc ]; } +subtest 'get_identifiers' => sub { + plan tests => 1; + + t::lib::Mocks::mock_preference( 'marcflavour', 'MARC21' ); + my $record = MARC::Record->new(); + $record->add_fields( + [ + '100', ' ', ' ', + a => 'Lastname, Firstname', + b => 'b', + c => 'c', + i => 'i' + ], + [ + '024', '', '', + a => '0000-0002-1234-5678', + 2 => 'orcid', + 6 => 'https://orcid.org/0000-0002-1234-5678' + ], + [ + '024', '', '', + a => '01234567890', + 2 => 'scopus', + 6 => 'https://www.scopus.com/authid/detail.uri?authorId=01234567890' + ], + ); + my $authid = C4::AuthoritiesMarc::AddAuthority($record, undef, 'PERSO_NAME'); + my $authority = Koha::Authorities->find($authid); + is_deeply( + $authority->get_identifiers, + [ + { + source => 'orcid', + number => '0000-0002-1234-5678', + }, + { + source => 'scopus', + number => '01234567890', + } + ] + ); +}; + +subtest 'record tests' => sub { + plan tests => 3; + + t::lib::Mocks::mock_preference( 'marcflavour', 'MARC21' ); + my $record = MARC::Record->new(); + $record->add_fields( + [ + '100', ' ', ' ', + a => 'Lastname, Firstname', + b => 'b', + c => 'c', + i => 'i' + ], + [ + '024', '', '', + a => '0000-0002-1234-5678', + 2 => 'orcid', + 6 => 'https://orcid.org/0000-0002-1234-5678' + ], + [ + '024', '', '', + a => '01234567890', + 2 => 'scopus', + 6 => 'https://www.scopus.com/authid/detail.uri?authorId=01234567890' + ], + ); + my $authid = C4::AuthoritiesMarc::AddAuthority($record, undef, 'PERSO_NAME'); + my $authority = Koha::Authorities->find($authid); + my $authority_record = $authority->record; + is ($authority_record->field('100')->subfield('a'), 'Lastname, Firstname'); + my @fields_024 = $authority_record->field('024'); + is ($fields_024[0]->subfield('a'), '0000-0002-1234-5678'); + is ($fields_024[1]->subfield('a'), '01234567890'); + +}; + $schema->storage->txn_rollback; From 7c51874ab8bce848bb4783982bd87590c269c218 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 29 Jan 2024 12:37:54 +1300 Subject: [PATCH 08/56] Increment version for 22.05.18 release Signed-off-by: Wainui Witika-Park --- Koha.pm | 2 +- installer/data/mysql/db_revs/220518000.pl | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100755 installer/data/mysql/db_revs/220518000.pl diff --git a/Koha.pm b/Koha.pm index f671fa9b07..148afdbac8 100644 --- a/Koha.pm +++ b/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 = "22.05.17.000"; +$VERSION = "22.05.18.000"; sub version { return $VERSION; diff --git a/installer/data/mysql/db_revs/220518000.pl b/installer/data/mysql/db_revs/220518000.pl new file mode 100755 index 0000000000..16696ce466 --- /dev/null +++ b/installer/data/mysql/db_revs/220518000.pl @@ -0,0 +1,7 @@ +use Modern::Perl; + +return { + bug_number => undef, + description => 'Koha 22.05.18 release', + up => sub {}, +} From 8589daa1103105a6657476eeb67927fcaca3cb62 Mon Sep 17 00:00:00 2001 From: Wainui Witika-Park Date: Mon, 29 Jan 2024 00:06:42 +0000 Subject: [PATCH 09/56] Update release notes for 22.05.18 release Signed-off-by: Wainui Witika-Park --- .../release_notes/release_notes_22_05_18.html | 292 ++++++++++++++++++ misc/release_notes/release_notes_22_05_18.md | 254 +++++++++++++++ 2 files changed, 546 insertions(+) create mode 100644 misc/release_notes/release_notes_22_05_18.html create mode 100644 misc/release_notes/release_notes_22_05_18.md diff --git a/misc/release_notes/release_notes_22_05_18.html b/misc/release_notes/release_notes_22_05_18.html new file mode 100644 index 0000000000..5bc7f2b645 --- /dev/null +++ b/misc/release_notes/release_notes_22_05_18.html @@ -0,0 +1,292 @@ +

RELEASE NOTES FOR KOHA 22.05.18

+ +

28 Jan 2024

+ +

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 22.05.18 can be downloaded from:

+ + + +

Installation instructions can be found at:

+ +
    +
  • Koha Wiki
  • +
  • OR in the INSTALL files that come in the tarball
  • +
+ +

Koha 22.05.18 is a bugfix/maintenance release.

+ +

It includes 1 enhancements, 2 bugfixes.

+ +

System requirements

+ +

You can learn about the system components (like OS and database) needed for running Koha on the community wiki.

+ +

Security bugs

+ +
    +
  • 34893 ILS-DI can return the wrong patron for AuthenticatePatron
  • +
+ +

Critical bugs fixed

+ +
    +
  • 35343 record method, required for bug 26611, missing from Koha::Authority
  • +
+ +

Enhancements

+ +
    +
  • 27342 Improve readability and improvement of C4::Auth::get_template_and_user
  • +
+ +

Documentation

+ +

The Koha manual is maintained in Sphinx. The home page for Koha +documentation is

+ + + +

The Git repository for the Koha manual can be found at

+ + + +

Translations

+ +

Complete or near-complete translations of the OPAC and staff +interface are available in this release for the following languages:

+ +
+ +- Arabic (ar_ARAB) (81%) +- Armenian (hy_ARMN) (100%) +- Bulgarian (bg_CYRL) (100%) +- Chinese (Traditional) (95%) +- Czech (68%) +- Dutch (83%) +- English (100%) +- English (New Zealand) (69%) +- English (USA) +- Finnish (95%) +- French (99%) +- French (Canada) (99%) +- German (100%) +- German (Switzerland) (61%) +- Greek (61%) +- Hindi (100%) +- Italian (100%) +- Norwegian Bokmål (60%) +- Persian (fa_ARAB) (68%) +- Polish (100%) +- Portuguese (Brazil) (83%) +- Portuguese (Portugal) (85%) +- Russian (77%) +- Slovak (71%) +- Spanish (100%) +- Swedish (87%) +- Telugu (85%) +- Turkish (99%) +- Ukrainian (73%) +- hyw_ARMN (generated) (hyw_ARMN) (76%) +
+ +

Partial translations are available for various other languages.

+ +

The Koha team welcomes additional translations; please see

+ + + +

For information about translating Koha, and join the koha-translate +list to volunteer:

+ + + +

The most up-to-date translations can be found at:

+ + + +

Release Team

+ +

The release team for Koha 22.05.18 is

+ +
    +
  • Release Manager: Katrin Fischer

  • +
  • Release Manager assistants:

    + +
      +
    • Tomás Cohen Arazi
    • +
    • Martin Renvoize
    • +
    • Jonathan Druart
    • +
  • +
  • QA Manager: Marcel de Rooy

  • +
  • QA Team:

    + +
      +
    • Marcel de Rooy
    • +
    • Julian Maurice
    • +
    • Lucas Gass
    • +
    • Victor Grousset
    • +
    • Kyle M Hall
    • +
    • Nick Clemens
    • +
    • Martin Renvoize
    • +
    • Tomás Cohen Arazi
    • +
    • Aleisha Amohia
    • +
    • Emily Lamancusa
    • +
    • David Cook
    • +
    • Jonathan Druart
    • +
    • Pedor Amorim
    • +
  • +
  • Topic Experts:

    + +
      +
    • UI Design -- Owen Leonard
    • +
    • Zebra -- Fridolin Somers
    • +
    • REST API -- Tomás Cohen Arazi
    • +
    • ERM -- Matt Blenkinsop
    • +
    • ILL -- Pedro Amorim
    • +
    • SIP2 -- Matthias Meusburger
    • +
    • CAS -- Matthias Meusburger
    • +
  • +
  • Bug Wranglers:

    + +
      +
    • Aleisha Amohia
    • +
    • Indranil Das Gupta
    • +
  • +
  • Packaging Managers:

    + +
      +
    • Mason James
    • +
    • Indranil Das Gupta
    • +
    • Tomás Cohen Arazi
    • +
  • +
  • Documentation Manager: Aude Charillon

  • +
  • Documentation Team:

    + +
      +
    • Caroline Cyr La Rose
    • +
    • Kelly McElligott
    • +
    • Philip Orr
    • +
    • Marie-Luce Laflamme
    • +
    • Lucy Vaux-Harvey
    • +
  • +
  • Translation Manager: Jonathan Druart

  • +
  • Wiki curators:

    + +
      +
    • Thomas Dukleth
    • +
    • Katrin Fischer
    • +
  • +
  • Release Maintainers:

    + +
      +
    • 23.11 -- Fridolin Somers
    • +
    • 23.05 -- Lucas Gass
    • +
    • 22.11 -- Frédéric Demians
    • +
    • 22.05 -- Danyon Sewell
    • +
  • +
  • Release Maintainer assistants:

    + +
      +
    • 22.05 -- Wainui Witika-Park
    • +
  • +
+ +

Credits

+ +

We thank the following individuals who contributed patches to Koha 22.05.18

+ +
+ +- Aleisha Amohia (1) +- Tomás Cohen Arazi (3) +- David Cook (1) +- Jonathan Druart (2) +- Kyle M Hall (3) +- Martin Renvoize (2) +- root (1) +- Wainui Witika-Park (1) +
+ +

We thank the following libraries, companies, and other institutions who contributed +patches to Koha 22.05.18

+ +
+ +- ByWater-Solutions (3) +- Catalyst (1) +- Catalyst Open Source Academy (1) +- Koha Community Developers (2) +- Prosentient Systems (1) +- PTFS-Europe (2) +- Theke Solutions (3) +- wainuiwitikapark-lp.dynamic.wgtn.cat-it.co.nz (1) +
+ +

We also especially thank the following individuals who tested patches +for Koha

+ +
+ +- Tomás Cohen Arazi (4) +- Matt Blenkinsop (1) +- Victor Grousset (4) +- Martin Renvoize (2) +- Wainui Witika-Park (6) +
+ +

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 master branch of:

+ + + +

The branch for this version of Koha and future bugfixes in this release +line is (HEAD detached from 63ec3760d2).

+ +

Bugs and feature requests

+ +

Bug reports and feature requests can be filed at the Koha bug +tracker at:

+ + + +

He rau ringa e oti ai. +(Many hands finish the work)

+ +

Autogenerated release notes updated last on 28 Jan 2024 23:58:58.

diff --git a/misc/release_notes/release_notes_22_05_18.md b/misc/release_notes/release_notes_22_05_18.md new file mode 100644 index 0000000000..cb3be8eb20 --- /dev/null +++ b/misc/release_notes/release_notes_22_05_18.md @@ -0,0 +1,254 @@ +# RELEASE NOTES FOR KOHA 22.05.18 +28 Jan 2024 + +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](http://koha-community.org) + +Koha 22.05.18 can be downloaded from: + +- [Download](http://download.koha-community.org/koha-22.05.18.tar.gz) + +Installation instructions can be found at: + +- [Koha Wiki](http://wiki.koha-community.org/wiki/Installation_Documentation) +- OR in the INSTALL files that come in the tarball + +Koha 22.05.18 is a bugfix/maintenance release. + +It includes 1 enhancements, 2 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 + +- [34893](http://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=34893) ILS-DI can return the wrong patron for AuthenticatePatron + +## Critical bugs fixed + +- [35343](http://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=35343) record method, required for bug 26611, missing from Koha::Authority + +## Enhancements + +- [27342](http://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=27342) Improve readability and improvement of C4::Auth::get_template_and_user + +## Documentation + +The Koha manual is maintained in Sphinx. The home page for Koha +documentation is + +- [Koha Documentation](http://koha-community.org/documentation/) +As of the date of these release notes, the Koha manual is available in the following languages: + +- [Chinese (Traditional)](https://koha-community.org/manual/22.05//html/) (50%) +- [English](https://koha-community.org/manual/22.05//html/) (100%) +- [English (USA)](https://koha-community.org/manual/22.05/en/html/) +- [French](https://koha-community.org/manual/22.05/fr/html/) (39%) +- [German](https://koha-community.org/manual/22.05/de/html/) (41%) +- [Hindi](https://koha-community.org/manual/22.05/hi/html/) (68%) + +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: +
+ +- Arabic (ar_ARAB) (81%) +- Armenian (hy_ARMN) (100%) +- Bulgarian (bg_CYRL) (100%) +- Chinese (Traditional) (95%) +- Czech (68%) +- Dutch (83%) +- English (100%) +- English (New Zealand) (69%) +- English (USA) +- Finnish (95%) +- French (99%) +- French (Canada) (99%) +- German (100%) +- German (Switzerland) (61%) +- Greek (61%) +- Hindi (100%) +- Italian (100%) +- Norwegian Bokmål (60%) +- Persian (fa_ARAB) (68%) +- Polish (100%) +- Portuguese (Brazil) (83%) +- Portuguese (Portugal) (85%) +- Russian (77%) +- Slovak (71%) +- Spanish (100%) +- Swedish (87%) +- Telugu (85%) +- Turkish (99%) +- Ukrainian (73%) +- hyw_ARMN (generated) (hyw_ARMN) (76%) +
+ +Partial translations are available for various other languages. + +The Koha team welcomes additional translations; please see + +- [Koha Translation Info](http://wiki.koha-community.org/wiki/Translating_Koha) + +For information about translating Koha, and join the koha-translate +list to volunteer: + +- [Koha Translate List](http://lists.koha-community.org/cgi-bin/mailman/listinfo/koha-translate) + +The most up-to-date translations can be found at: + +- [Koha Translation](http://translate.koha-community.org/) + +## Release Team + +The release team for Koha 22.05.18 is + + +- Release Manager: Katrin Fischer + +- Release Manager assistants: + - Tomás Cohen Arazi + - Martin Renvoize + - Jonathan Druart + +- QA Manager: Marcel de Rooy + +- QA Team: + - Marcel de Rooy + - Julian Maurice + - Lucas Gass + - Victor Grousset + - Kyle M Hall + - Nick Clemens + - Martin Renvoize + - Tomás Cohen Arazi + - Aleisha Amohia + - Emily Lamancusa + - David Cook + - Jonathan Druart + - Pedor Amorim + +- Topic Experts: + - UI Design -- Owen Leonard + - Zebra -- Fridolin Somers + - REST API -- Tomás Cohen Arazi + - ERM -- Matt Blenkinsop + - ILL -- Pedro Amorim + - SIP2 -- Matthias Meusburger + - CAS -- Matthias Meusburger + +- Bug Wranglers: + - Aleisha Amohia + - Indranil Das Gupta + +- Packaging Managers: + - Mason James + - Indranil Das Gupta + - Tomás Cohen Arazi + +- Documentation Manager: Aude Charillon + +- Documentation Team: + - Caroline Cyr La Rose + - Kelly McElligott + - Philip Orr + - Marie-Luce Laflamme + - Lucy Vaux-Harvey + +- Translation Manager: Jonathan Druart + + +- Wiki curators: + - Thomas Dukleth + - Katrin Fischer + +- Release Maintainers: + - 23.11 -- Fridolin Somers + - 23.05 -- Lucas Gass + - 22.11 -- Frédéric Demians + - 22.05 -- Danyon Sewell + +- Release Maintainer assistants: + - 22.05 -- Wainui Witika-Park + +## Credits + + + +We thank the following individuals who contributed patches to Koha 22.05.18 +
+ +- Aleisha Amohia (1) +- Tomás Cohen Arazi (3) +- David Cook (1) +- Jonathan Druart (2) +- Kyle M Hall (3) +- Martin Renvoize (2) +- root (1) +- Wainui Witika-Park (1) +
+ +We thank the following libraries, companies, and other institutions who contributed +patches to Koha 22.05.18 +
+ +- ByWater-Solutions (3) +- Catalyst (1) +- Catalyst Open Source Academy (1) +- Koha Community Developers (2) +- Prosentient Systems (1) +- PTFS-Europe (2) +- Theke Solutions (3) +- wainuiwitikapark-lp.dynamic.wgtn.cat-it.co.nz (1) +
+ +We also especially thank the following individuals who tested patches +for Koha +
+ +- Tomás Cohen Arazi (4) +- Matt Blenkinsop (1) +- Victor Grousset (4) +- Martin Renvoize (2) +- Wainui Witika-Park (6) +
+ + + + + +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 master 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 (HEAD detached from 63ec3760d2). + +## Bugs and feature requests + +Bug reports and feature requests can be filed at the Koha bug +tracker at: + +- [Koha Bugzilla](http://bugs.koha-community.org) + +He rau ringa e oti ai. +(Many hands finish the work) + +Autogenerated release notes updated last on 28 Jan 2024 23:58:58. From d7041a36cc62e739b5bdddffb2497337d9c5cdf3 Mon Sep 17 00:00:00 2001 From: Marcel de Rooy Date: Tue, 13 Feb 2024 12:36:44 +0000 Subject: [PATCH 10/56] Bug 36072: opac-request-article should check syspref Note: This is handled now just like opac-reserve. Test plan: Disable ArticleRequests and hit the page. Signed-off-by: Marcel de Rooy Signed-off-by: Martin Renvoize Signed-off-by: Wainui Witika-Park --- opac/opac-request-article.pl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/opac/opac-request-article.pl b/opac/opac-request-article.pl index dcf9f214a5..3fdb402118 100755 --- a/opac/opac-request-article.pl +++ b/opac/opac-request-article.pl @@ -33,6 +33,12 @@ use Try::Tiny; my $cgi = CGI->new; +# If ArticleRequests is disabled, leave immediately +if ( !C4::Context->preference('ArticleRequests') ) { + print $cgi->redirect("/cgi-bin/koha/errors/404.pl"); + exit; +} + my ( $template, $borrowernumber, $cookie ) = get_template_and_user( { template_name => "opac-request-article.tt", From bdd288e3c464683ede8b22e20b4359083ef81fd1 Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Tue, 30 Jan 2024 14:53:03 +0100 Subject: [PATCH 11/56] Bug 35941: Limit club list to those from the logged in user clubs-tab get the patron's id from the parameter. At the OPAC we must use the one from the logged in user, to prevent leak to other users Test plan: Have 2 clubs: A, B Enroll to A with patron borrowernumber=1 Enroll to B with patron borrowernumber=2 Log in with patron 1 and hit: http://localhost:8080/cgi-bin/koha/clubs/clubs-tab.pl?borrowernumber=1 => OK Now hit http://localhost:8080/cgi-bin/koha/clubs/clubs-tab.pl?borrowernumber=2 => oops Apply this patch, try again. The "borrowernumber" parameter is no longer used to fetch the club list. Signed-off-by: Kyle M Hall Signed-off-by: Martin Renvoize Signed-off-by: Wainui Witika-Park --- .../opac-tmpl/bootstrap/en/modules/clubs/clubs-tab.tt | 8 ++++---- .../opac-tmpl/bootstrap/en/modules/clubs/enroll.tt | 3 +-- opac/clubs/clubs-tab.pl | 10 ++++------ opac/clubs/enroll.pl | 8 ++------ 4 files changed, 11 insertions(+), 18 deletions(-) diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/clubs/clubs-tab.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/clubs/clubs-tab.tt index 4358d097a3..5c0364ffb2 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/clubs/clubs-tab.tt +++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/clubs/clubs-tab.tt @@ -55,8 +55,8 @@ [% c.name | html %] [% c.description | html %] - [% IF !c.club_template.is_email_required || ( c.club_template.is_email_required && borrower.first_valid_email_address ) %] - [% ELSE %] @@ -72,7 +72,7 @@