diff --git a/C4/Auth.pm b/C4/Auth.pm index 1a6141c372..4cd0fe80ea 100644 --- a/C4/Auth.pm +++ b/C4/Auth.pm @@ -82,14 +82,9 @@ BEGIN { get_template_and_user haspermission create_basic_session ); - $ldap = C4::Context->config('useldapserver') || 0; $cas = C4::Context->preference('casAuthentication'); $caslogout = C4::Context->preference('casLogout'); - if ($ldap) { - require C4::Auth_with_ldap; - import C4::Auth_with_ldap qw(checkpw_ldap); - } if ($cas) { require C4::Auth_with_cas; # no import import C4::Auth_with_cas qw(check_api_auth_cas checkpw_cas login_cas logout_cas login_cas_url logout_if_required multipleAuth getMultipleAuth); @@ -554,9 +549,9 @@ sub get_template_and_user { my $opac_limit_override = $ENV{'OPAC_LIMIT_OVERRIDE'}; my $opac_name = ''; if ( - ( $opac_limit_override && $opac_search_limit && $opac_search_limit =~ /branch:([\w-]+)/ ) || - ( $in->{'query'}->param('limit') && $in->{'query'}->param('limit') =~ /branch:([\w-]+)/ ) || - ( $in->{'query'}->param('limit') && $in->{'query'}->param('limit') =~ /multibranchlimit:(\w+)/ ) + ( $opac_limit_override && $opac_search_limit && $opac_search_limit =~ /^branch:([\w-]+)/ ) || + ( $in->{'query'}->param('limit') && $in->{'query'}->param('limit') =~ /^branch:([\w-]+)/ ) || + ( $in->{'query'}->param('limit') && $in->{'query'}->param('limit') =~ /^multibranchlimit:(\w+)/ ) ) { $opac_name = $1; # opac_search_limit is a branch, so we use it. } elsif ( $in->{'query'}->param('multibranchlimit') ) { @@ -1418,6 +1413,11 @@ sub checkauth { my $auth_error = $query->param('auth_error'); my $auth_template_name = ( $type eq 'opac' ) ? 'opac-auth.tt' : 'auth.tt'; my $template = C4::Templates::gettemplate( $auth_template_name, $type, $query ); + + my $borrowernumber = $patron and $patron->borrowernumber; + my $anonymous_patron = C4::Context->preference('AnonymousPatron'); + my $is_anonymous_patron = $patron && ( $patron->borrowernumber eq $anonymous_patron ); + $template->param( login => 1, INPUTS => \@inputs, @@ -1452,6 +1452,7 @@ sub checkauth { opac_css_override => $ENV{'OPAC_CSS_OVERRIDE'}, too_many_login_attempts => ( $patron and $patron->account_locked ), password_has_expired => ( $patron and $patron->password_expired ), + is_anonymous_patron => ( $is_anonymous_patron ), auth_error => $auth_error, ); @@ -1981,20 +1982,24 @@ sub checkpw { my $shib = C4::Context->config('useshibboleth') && shib_ok(); my $shib_login = $shib ? get_login_shib() : undef; + my $anonymous_patron = C4::Context->preference('AnonymousPatron'); + my @return; my $check_internal_as_fallback = 0; my $passwd_ok = 0; my $patron; - # Note: checkpw_* routines returns: # 1 if auth is ok # 0 if auth is nok # -1 if user bind failed (LDAP only) - + $ldap = C4::Context->config('useldapserver') || 0; if ( $ldap && defined($password) ) { my ( $retval, $retcard, $retuserid ); - ( $retval, $retcard, $retuserid, $patron ) = checkpw_ldap(@_); # EXTERNAL AUTH + require C4::Auth_with_ldap; + import C4::Auth_with_ldap qw(checkpw_ldap); + + ( $retval, $retcard, $retuserid, $patron ) = C4::Auth_with_ldap::checkpw_ldap(@_); # EXTERNAL AUTH if ( $retval == 1 ) { @return = ( $retval, $retcard, $retuserid, $patron ); $passwd_ok = 1; @@ -2058,7 +2063,9 @@ sub checkpw { @return = (); } elsif ($passwd_ok) { $patron->update( { login_attempts => 0 } ); - if ( $patron->password_expired ) { + if ( defined($anonymous_patron) && ($patron->borrowernumber eq $anonymous_patron) ) { + @return = ( -3, $patron ); + } elsif ( $patron->password_expired ) { @return = ( -2, $patron ); } } else { diff --git a/C4/Auth_with_ldap.pm b/C4/Auth_with_ldap.pm index f0993c89ba..406e0d9a19 100644 --- a/C4/Auth_with_ldap.pm +++ b/C4/Auth_with_ldap.pm @@ -227,6 +227,7 @@ sub checkpw_ldap { map { exists( $borrower{$_} ) ? ( $_ => $borrower{$_} ) : () } @columns } )->store; + $patron->discard_changes; die "Insert of new patron failed" unless $patron; $borrowernumber = $patron->borrowernumber; C4::Members::Messaging::SetMessagingPreferencesFromDefaults( diff --git a/C4/Auth_with_shibboleth.pm b/C4/Auth_with_shibboleth.pm index 3e6f42b57c..e3eb281cfc 100644 --- a/C4/Auth_with_shibboleth.pm +++ b/C4/Auth_with_shibboleth.pm @@ -135,6 +135,8 @@ sub _autocreate { } my $patron = Koha::Patron->new( \%borrower )->store; + $patron->discard_changes; + C4::Members::Messaging::SetMessagingPreferencesFromDefaults( { borrowernumber => $patron->borrowernumber, diff --git a/C4/AuthoritiesMarc.pm b/C4/AuthoritiesMarc.pm index 1656a2ba9b..4fe55cd34b 100644 --- a/C4/AuthoritiesMarc.pm +++ b/C4/AuthoritiesMarc.pm @@ -323,17 +323,17 @@ sub SearchAuthorities { if ( C4::Context->preference('ShowHeadingUse') ) { # checking valid heading use my $f008 = $authrecord->field('008'); - my $pos14to16 = substr( $f008->data, 14, 3 ); - my $main = substr( $pos14to16, 0, 1 ); - $newline{main} = 1 if $main eq 'a'; - my $subject = substr( $pos14to16, 1, 1); - $newline{subject} = 1 if $subject eq 'a'; - my $series = substr( $pos14to16, 2, 1 ); - $newline{series} = 1 if $series eq 'a'; + if ($f008) { + my $pos14to16 = substr( $f008->data, 14, 3 ); + my $main = substr( $pos14to16, 0, 1 ); + $newline{main} = 1 if $main eq 'a'; + my $subject = substr( $pos14to16, 1, 1 ); + $newline{subject} = 1 if $subject eq 'a'; + my $series = substr( $pos14to16, 2, 1 ); + $newline{series} = 1 if $series eq 'a'; + } } - - $newline{authtype} = defined($thisauthtype) ? - $thisauthtype->authtypetext : ''; + $newline{authtype} = defined($thisauthtype) ? $thisauthtype->authtypetext : ''; $newline{summary} = $summary; $newline{even} = $counter % 2; $newline{reported_tag} = $reported_tag; diff --git a/C4/Barcodes.pm b/C4/Barcodes.pm index 957d60f283..333a8eb8bc 100644 --- a/C4/Barcodes.pm +++ b/C4/Barcodes.pm @@ -94,11 +94,12 @@ sub max { return $self->db_max; } sub db_max { - my $self = shift; - my $query = "SELECT max(abs(barcode)) FROM items LIMIT 1"; # Possible problem if multiple barcode types populated - my $sth = C4::Context->dbh->prepare($query); - $sth->execute(); - return $sth->fetchrow_array || $self->initial; + my $self = shift; + my $query = "SELECT max(abs(CAST(barcode AS UNSIGNED))) FROM items LIMIT 1" + ; # Possible problem if multiple barcode types populated + my $sth = C4::Context->dbh->prepare($query); + $sth->execute(); + return $sth->fetchrow_array || $self->initial; } sub next_value { my $self = shift; diff --git a/C4/Biblio.pm b/C4/Biblio.pm index 3f48dbb8df..ffce275c7a 100644 --- a/C4/Biblio.pm +++ b/C4/Biblio.pm @@ -555,9 +555,13 @@ sub DelBiblio { # We delete any existing holds my $holds = $biblio->holds; + $holds->update( { deleted_biblionumber => $biblionumber }, { no_triggers => 1 } ); + my $old_holds = $biblio->old_holds; + $old_holds->update( { deleted_biblionumber => $biblionumber }, { no_triggers => 1 } ); while ( my $hold = $holds->next ) { + # no need to update the holds queue on each step, we'll do it at the end - $hold->cancel({ skip_holds_queue => 1 }); + $hold->cancel( { skip_holds_queue => 1 } ); } # We update any existing orders diff --git a/C4/Circulation.pm b/C4/Circulation.pm index e90cd1c37c..5844172556 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -1266,9 +1266,8 @@ sub CanBookBeIssued { ## CHECK AGE RESTRICTION my $agerestriction = $biblioitem->agerestriction; - my ( $restriction_age, $daysToAgeRestriction ) = - GetAgeRestriction( $agerestriction, $patron->unblessed ); - if ( $daysToAgeRestriction && $daysToAgeRestriction > 0 ) { + my $restriction_age = GetAgeRestriction( $agerestriction ); + if ( $restriction_age && $patron->dateofbirth && $restriction_age > $patron->get_age() ) { if ( C4::Context->preference('AgeRestrictionOverride') ) { $needsconfirmation{AGE_RESTRICTION} = "$agerestriction"; } @@ -2461,7 +2460,7 @@ sub AddReturn { ccode => $item->ccode, categorycode => $categorycode, interface => C4::Context->interface, - }) unless ( $skip_localuse && $stat_type eq 'localuse' ); + }) unless ( $skip_localuse && !$issue ); # Send a check-in slip. # NOTE: borrower may be undef. Do not try to send messages then. if ( $patron ) { @@ -4421,21 +4420,15 @@ sub IsItemIssued { =head2 GetAgeRestriction - my ($ageRestriction, $daysToAgeRestriction) = GetAgeRestriction($record_restrictions, $borrower); - my ($ageRestriction, $daysToAgeRestriction) = GetAgeRestriction($record_restrictions); - - if($daysToAgeRestriction <= 0) { #Borrower is allowed to access this material, as they are older or as old as the agerestriction } - if($daysToAgeRestriction > 0) { #Borrower is this many days from meeting the agerestriction } + my $ageRestriction = GetAgeRestriction($record_restrictions); @PARAM1 the koha.biblioitems.agerestriction value, like K18, PEGI 13, ... -@PARAM2 a borrower-object with koha.borrowers.dateofbirth. (OPTIONAL) -@RETURNS The age restriction age in years and the days to fulfill the age restriction for the given borrower. - Negative days mean the borrower has gone past the age restriction age. +@RETURNS The age restriction age in years. =cut sub GetAgeRestriction { - my ($record_restrictions, $borrower) = @_; + my ($record_restrictions) = @_; my $markers = C4::Context->preference('AgeRestrictionMarker'); return unless $record_restrictions; @@ -4470,26 +4463,7 @@ sub GetAgeRestriction { last if ( $restriction_year > 0 ); } - #Check if the borrower is age restricted for this material and for how long. - if ($restriction_year && $borrower) { - if ( $borrower->{'dateofbirth'} ) { - my @alloweddate = split /-/, $borrower->{'dateofbirth'}; - $alloweddate[0] += $restriction_year; - - #Prevent runime eror on leap year (invalid date) - if ( ( $alloweddate[1] == 2 ) && ( $alloweddate[2] == 29 ) ) { - $alloweddate[2] = 28; - } - - #Get how many days the borrower has to reach the age restriction - my @Today = split /-/, dt_from_string()->ymd(); - my $daysToAgeRestriction = Date_to_Days(@alloweddate) - Date_to_Days(@Today); - #Negative days means the borrower went past the age restriction age - return ($restriction_year, $daysToAgeRestriction); - } - } - - return ($restriction_year); + return $restriction_year; } diff --git a/C4/ILSDI/Services.pm b/C4/ILSDI/Services.pm index 48e5bf6e40..8adc0b7d2d 100644 --- a/C4/ILSDI/Services.pm +++ b/C4/ILSDI/Services.pm @@ -218,7 +218,7 @@ sub GetRecords { my $biblioitem = $biblio->biblioitem->unblessed; - my $record = $biblio->metadata->record({ embed_items => 1 }); + my $record = $biblio->metadata->record({ embed_items => 1, opac => 1, }); if ($record) { $biblioitem->{marcxml} = $record->as_xml_record( C4::Context->preference('marcflavour') ); } @@ -236,7 +236,7 @@ sub GetRecords { foreach my $checkout (@$checkouts) { delete $checkout->{'borrowernumber'}; } - my @items = $biblio->items->as_list; + my @items = $biblio->items->filter_by_visible_in_opac->as_list; $biblioitem->{items}->{item} = []; diff --git a/C4/ImportExportFramework.pm b/C4/ImportExportFramework.pm index d02ec43d57..ad626b679f 100644 --- a/C4/ImportExportFramework.pm +++ b/C4/ImportExportFramework.pm @@ -291,6 +291,7 @@ sub _export_table_csv for my $field (@fields) { my $value = $hashRef->{$field} // q||; $value =~ s/[\r\n]//g; + $value =~ s/"/""/g; $$strCSV .= '"' . $value . '",'; } chop $$strCSV; diff --git a/C4/Items.pm b/C4/Items.pm index 519e6d1471..a91279b665 100644 --- a/C4/Items.pm +++ b/C4/Items.pm @@ -45,6 +45,7 @@ BEGIN { } use Carp qw( croak ); +use C4::Circulation qw( barcodedecode ); use C4::Context; use C4::Koha; use C4::Biblio qw( GetMarcStructure TransformMarcToKoha ); @@ -459,11 +460,15 @@ sub CheckItemPreSave { my %errors = (); # check for duplicate barcode - if (exists $item_ref->{'barcode'} and defined $item_ref->{'barcode'}) { - my $existing_item= Koha::Items->find({barcode => $item_ref->{'barcode'}}); + if ( exists $item_ref->{'barcode'} and defined $item_ref->{'barcode'} ) { + my $barcode = C4::Circulation::barcodedecode( $item_ref->{'barcode'} ); + my $existing_item = Koha::Items->find( { barcode => $barcode } ); if ($existing_item) { - if (!exists $item_ref->{'itemnumber'} # new item - or $item_ref->{'itemnumber'} != $existing_item->itemnumber) { # existing item + if ( + !exists $item_ref->{'itemnumber'} # new item + or $item_ref->{'itemnumber'} != $existing_item->itemnumber + ) + { # existing item $errors{'duplicate_barcode'} = $item_ref->{'barcode'}; } } @@ -1178,7 +1183,7 @@ sub SearchItems { LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber LEFT JOIN biblio_metadata ON biblio_metadata.biblionumber = biblio.biblionumber - LEFT JOIN issues ON issues.itemnumber = items.itemnumber + LEFT JOIN issues USING (itemnumber) WHERE 1 }; if (defined $where_str and $where_str ne '') { diff --git a/C4/Letters.pm b/C4/Letters.pm index 273b1fef21..10c7e2ee9a 100644 --- a/C4/Letters.pm +++ b/C4/Letters.pm @@ -1569,8 +1569,8 @@ sub _wrap_html { $css = qq{} if $css; return < - + "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + $title diff --git a/C4/Overdues.pm b/C4/Overdues.pm index a2494f7f1e..7faa2e9f21 100644 --- a/C4/Overdues.pm +++ b/C4/Overdues.pm @@ -288,10 +288,12 @@ sub CalcFine { && $amount > $issuing_rule->{overduefinescap}; # This must be moved to Koha::Item (see also similar code in C4::Accounts::chargelostitem - $item->{replacementprice} ||= $itemtype->defaultreplacecost - if $itemtype - && ( ! defined $item->{replacementprice} || $item->{replacementprice} == 0 ) - && C4::Context->preference("useDefaultReplacementCost"); + if ( $itemtype + && ( !defined $item->{replacementprice} || $item->{replacementprice} + .0 == 0 ) + && C4::Context->preference("useDefaultReplacementCost") ) + { + $item->{replacementprice} = $itemtype->defaultreplacecost; + } $amount = $item->{replacementprice} if ( $issuing_rule->{cap_fine_to_replacement_price} && $item->{replacementprice} && $amount > $item->{replacementprice} ); diff --git a/C4/Reserves.pm b/C4/Reserves.pm index 6624fe9082..bc96dc9c3c 100644 --- a/C4/Reserves.pm +++ b/C4/Reserves.pm @@ -44,7 +44,6 @@ use Koha::Holds; use Koha::ItemTypes; use Koha::Items; use Koha::Libraries; -use Koha::Old::Holds; use Koha::Patrons; use Koha::Plugins; use Koha::Policy::Holds; @@ -485,10 +484,6 @@ sub CanItemBeReserved { } } - # we retrieve borrowers and items informations # - # item->{itype} will come for biblioitems if necessery - my $borrower = $patron->unblessed; - # If an item is damaged and we don't allow holds on damaged items, we can stop right here return _cache { status =>'damaged' } if ( $item->damaged @@ -497,9 +492,8 @@ sub CanItemBeReserved { if( GetMarcFromKohaField('biblioitems.agerestriction') ){ my $biblio = $item->biblio; # Check for the age restriction - my ( $ageRestriction, $daysToAgeRestriction ) = - C4::Circulation::GetAgeRestriction( $biblio->biblioitem->agerestriction, $borrower ); - return _cache { status => 'ageRestricted' } if $daysToAgeRestriction && $daysToAgeRestriction > 0; + my $ageRestriction = C4::Circulation::GetAgeRestriction( $biblio->biblioitem->agerestriction ); + return _cache { status => 'ageRestricted' } if $ageRestriction && $patron->dateofbirth && $ageRestriction > $patron->get_age(); } # Check that the patron doesn't have an item level hold on this item already @@ -527,14 +521,14 @@ sub CanItemBeReserved { } elsif ( $controlbranch eq "PatronLibrary" ) { $branchfield = "borrowers.branchcode"; - $reserves_control_branch = $borrower->{branchcode}; + $reserves_control_branch = $patron->branchcode; } # we retrieve rights if ( my $reservesallowed = Koha::CirculationRules->get_effective_rule({ itemtype => $item->effective_itemtype, - categorycode => $borrower->{categorycode}, + categorycode => $patron->categorycode, branchcode => $reserves_control_branch, rule_name => 'reservesallowed', }) @@ -547,7 +541,7 @@ sub CanItemBeReserved { } my $rights = Koha::CirculationRules->get_effective_rules({ - categorycode => $borrower->{'categorycode'}, + categorycode => $patron->categorycode, itemtype => $item->effective_itemtype, branchcode => $reserves_control_branch, rules => ['holds_per_record','holds_per_day'] @@ -656,7 +650,7 @@ sub CanItemBeReserved { } if ( $branchitemrule->{holdallowed} eq 'from_home_library' - && $borrower->{branchcode} ne $item->homebranch ) + && $patron->branchcode ne $item->homebranch ) { return _cache { status => 'cannotReserveFromOtherBranches' }; } @@ -685,7 +679,7 @@ sub CanItemBeReserved { if ($branchitemrule->{hold_fulfillment_policy} eq 'holdgroup' && !$item_library->validate_hold_sibling( {branchcode => $pickup_branchcode} )) { return _cache { status => 'pickupNotInHoldGroup' }; } - if ($branchitemrule->{hold_fulfillment_policy} eq 'patrongroup' && !Koha::Libraries->find({branchcode => $borrower->{branchcode}})->validate_hold_sibling({branchcode => $pickup_branchcode})) { + if ($branchitemrule->{hold_fulfillment_policy} eq 'patrongroup' && !Koha::Libraries->find({branchcode => $patron->branchcode})->validate_hold_sibling({branchcode => $pickup_branchcode})) { return _cache { status => 'pickupNotInHoldGroup' }; } } @@ -1602,6 +1596,7 @@ sub _FixPriority { $hold = Koha::Holds->find( $reserve_id ); if (!defined $hold){ # may have already been checked out and hold fulfilled + require Koha::Old::Holds; $hold = Koha::Old::Holds->find( $reserve_id ); } return unless $hold; diff --git a/C4/SIP/ILS.pm b/C4/SIP/ILS.pm index 3e77abf602..7b0addd61b 100644 --- a/C4/SIP/ILS.pm +++ b/C4/SIP/ILS.pm @@ -311,7 +311,7 @@ sub end_patron_session { my ($self, $patron_id) = @_; # success?, screen_msg, print_line - return (1, 'Thank you !', ''); + return (1, 'Thank you!', ''); } sub pay_fee { diff --git a/C4/SIP/ILS/Patron.pm b/C4/SIP/ILS/Patron.pm index f3dfea74bd..c62fb51b53 100644 --- a/C4/SIP/ILS/Patron.pm +++ b/C4/SIP/ILS/Patron.pm @@ -121,6 +121,9 @@ sub new { } } + # Get currency 3 chars max + my $currency = substr Koha::Acquisition::Currencies->get_active->currency, 0, 3; + my $circ_blocked =( C4::Context->preference('OverduesBlockCirc') ne "noblock" && defined $flags->{ODUES}->{itemlist} ) ? 1 : 0; { no warnings; # any of these $kp->{fields} being concat'd could be undef @@ -164,6 +167,7 @@ sub new { fine_blocked => $fine_blocked, fee_limit => $fee_limit, userid => $kp->{userid}, + currency => $currency, ); } @@ -205,7 +209,7 @@ sub new { } } - # FIXME: populate fine_items recall_items + # FIXME: populate recall_items $ilspatron{unavail_holds} = _get_outstanding_holds($kp->{borrowernumber}); my $pending_checkouts = $patron->pending_checkouts; @@ -390,6 +394,7 @@ sub x_items { my $item_list = []; if ($self->{$array_var}) { + if ($start && $start > 1) { --$start; } @@ -397,6 +402,7 @@ sub x_items { $start = 0; } if ( $end && $end < @{$self->{$array_var}} ) { + --$end; } else { $end = @{$self->{$array_var}}; @@ -430,29 +436,33 @@ sub charged_items { return $self->x_items('items', @_); } sub fine_items { + require Koha::Database; require Template; - my $self = shift; - my $start = shift; - my $end = shift; + my $self = shift; + my $start = shift; + my $end = shift; my $server = shift; - my @fees = Koha::Database->new()->schema()->resultset('Accountline')->search( + my @fees = + Koha::Database->new()->schema()->resultset('Accountline')->search( { borrowernumber => $self->{borrowernumber}, amountoutstanding => { '>' => '0' }, } - ); + ); $start = $start ? $start - 1 : 0; $end = $end ? $end - 1 : scalar @fees - 1; - my $av_field_template = $server ? $server->{account}->{av_field_template} : undef; - $av_field_template ||= "[% accountline.description %] [% accountline.amountoutstanding | format('%.2f') %]"; + my $av_field_template = + $server ? $server->{account}->{av_field_template} : undef; + $av_field_template ||= +"[% accountline.description %] [% accountline.amountoutstanding | format('%.2f') %]"; my @return_values; - for ( my $i = $start; $i <= $end; $i++ ) { + for ( my $i = $start ; $i <= $end ; $i++ ) { my $fee = $fees[$i]; next unless $fee; @@ -462,7 +472,9 @@ sub fine_items { } return \@return_values; + } + sub recall_items { my $self = shift; return $self->x_items('recall_items', @_); diff --git a/C4/SIP/SIPServer.pm b/C4/SIP/SIPServer.pm index d26f5e25e6..96c1809fbe 100644 --- a/C4/SIP/SIPServer.pm +++ b/C4/SIP/SIPServer.pm @@ -8,7 +8,7 @@ use FindBin qw($Bin); use lib "$Bin"; use Net::Server::PreFork; use IO::Socket::INET; -use Socket qw(:DEFAULT :crlf); +use Socket qw(:DEFAULT :crlf TCP_KEEPIDLE TCP_KEEPINTVL IPPROTO_TCP); use Scalar::Util qw(blessed); require UNIVERSAL::require; @@ -90,6 +90,126 @@ push @parms, 'group=' . $>; # This is the main event. __PACKAGE__ ->run(@parms); +# +# Server +# + +=head3 options + +As per Net::Server documentation, override "options" to provide your own +custom options to the Net::Server* object. This allows us to use the Net::Server +infrastructure for configuration rather than hacking our own configuration into the +object. + +=cut + +sub options { + my $self = shift; + my $prop = $self->{'server'}; + my $template = shift; + + # setup options in the parent classes + $self->SUPER::options($template); + + $prop->{'custom_tcp_keepalive'} ||= undef; + $template->{'custom_tcp_keepalive'} = \$prop->{'custom_tcp_keepalive'}; + + $prop->{'custom_tcp_keepalive_time'} ||= undef; + $template->{'custom_tcp_keepalive_time'} = \$prop->{'custom_tcp_keepalive_time'}; + + $prop->{'custom_tcp_keepalive_intvl'} ||= undef; + $template->{'custom_tcp_keepalive_intvl'} = \$prop->{'custom_tcp_keepalive_intvl'}; +} + +=head3 post_configure_hook + +As per Net::Server documentation, this method validates our custom configuration. + +=cut + +sub post_configure_hook { + my $self = shift; + my $prop = $self->{'server'}; + if ( defined $prop->{'custom_tcp_keepalive'} && $prop->{'custom_tcp_keepalive'} ) { + + #NOTE: Any true value defined is forced to 1 just for the sake of predictability + $prop->{'custom_tcp_keepalive'} = 1; + } + + foreach my $key ( 'custom_tcp_keepalive_time', 'custom_tcp_keepalive_intvl' ) { + my $value = $prop->{$key}; + + #NOTE: A regex is used here to detect a positive integer, as int() returns integers but does not validate them + #NOTE: We do not allow zero as it can lead to problematic behaviour + if ( $value && $value =~ /^\d+$/ ) { + + #NOTE: Strictly, you must convert into an integer as a string will cause setsockopt to fail + $prop->{$key} = int($value); + } + } +} + +=head3 post_accept_hook + +This hook occurs after the client connection socket is created, which gives +us an opportunity to enable support for TCP keepalives using the SO_KEEPALIVE +socket option. + +By default, the kernel-level defaults (in seconds) are used. You can view these in the output of "sysctl -a": +net.ipv4.tcp_keepalive_intvl = 75 +net.ipv4.tcp_keepalive_time = 7200 + +Alternatively, you can use "custom_tcp_keepalive_time" and "custom_tcp_keepalive_intvl" to define +your own custom values for the socket. Note that these parameters are defined at the top server-level +and not on the listener-level. + +If you lower "custom_tcp_keepalive_time" below 75, you will also need to set "custom_tcp_keepalive_intvl". +The "tcp_keepalive_time" is the initial time used for the keepalive timer, and the "tcp_keepalive_intvl" +is the time used for subsequent keepalive timers. However, timers only send keepalive ACKs if the idle time +elapsed is greater than "tcp_keepalive_time". + +Thus, if "tcp_keepalive_time = 10" and "tcp_keepalive_intvl = 5", a keepalive ACK will be sent every 10 seconds +of idle time. If "tcp_keepalive_intvl = 10" and "tcp_keepalive_time = 5", a keepalive ACK will be sent after 5 +seconds of idle time, and the next keepalive ACK will be sent after 10 seconds of idle time. Generally speaking, +it's best to set "tcp_keepalive_time" to be higher than "tcp_keepalive_intvl". + +Reminder: once these settings are set on the socket, they are handled by the operating system kernel, and not +by the SIP server application. If you are having trouble with your settings, monitor your TCP traffic using +a tool such as "tcpdump" to review and refine how they work. + +=cut + +sub post_accept_hook { + my $self = shift; + my $prop = $self->{'server'}; + my $client = shift || $prop->{'client'}; + + my $tcp_keepalive = $prop->{custom_tcp_keepalive}; + my $tcp_keepalive_time = $prop->{custom_tcp_keepalive_time}; + my $tcp_keepalive_intvl = $prop->{custom_tcp_keepalive_intvl}; + + if ($tcp_keepalive) { + + #NOTE: set the SO_KEEPALIVE option to enable TCP keepalives + setsockopt( $client, SOL_SOCKET, SO_KEEPALIVE, 1 ) + or die "Unable to set SO_KEEPALIVE: $!"; + + if ($tcp_keepalive_time) { + + #NOTE: override "net.ipv4.tcp_keepalive_time" kernel parameter for this socket + setsockopt( $client, IPPROTO_TCP, TCP_KEEPIDLE, $tcp_keepalive_time ) + or die "Unable to set TCP_KEEPIDLE: $!"; + } + + if ($tcp_keepalive_intvl) { + + #NOTE: override "net.ipv4.tcp_keepalive_intvl" kernel parameter for this socket + setsockopt( $client, IPPROTO_TCP, TCP_KEEPINTVL, $tcp_keepalive_intvl ) + or die "Unable to set TCP_KEEPINTVL: $!"; + } + } +} + # # Child # diff --git a/C4/SIP/Sip.pm b/C4/SIP/Sip.pm index c29bff282f..667e0c83ac 100644 --- a/C4/SIP/Sip.pm +++ b/C4/SIP/Sip.pm @@ -187,34 +187,33 @@ sub boolspace { # sub write_msg { - my ($self, $msg, $file, $terminator, $encoding) = @_; + my ( $self, $msg, $server ) = @_; + my $terminator = $server->{account}->{terminator}; + my $encoding = $server->{account}->{encoding}; $terminator ||= q{}; $terminator = ( $terminator eq 'CR' ) ? $CR : $CRLF; - $msg = encode($encoding, $msg) if ( $encoding ); + my $separator = $server->{account}->{convert_nonprinting_characters}; + $msg =~ s/[^[:print:]]/$separator/g if defined $separator; + + $msg = encode( $encoding, $msg ) if ($encoding); my $cksum; # $msg = encode_utf8($msg); if ($error_detection) { - if (defined($self->{seqno})) { + if ( defined( $self->{seqno} ) ) { $msg .= 'AY' . $self->{seqno}; } $msg .= 'AZ'; $cksum = checksum($msg); - $msg .= sprintf('%04.4X', $cksum); + $msg .= sprintf( '%04.4X', $cksum ); } - - if ($file) { - $file->autoflush(1); - print $file $msg, $terminator; - } else { - STDOUT->autoflush(1); - print $msg, $terminator; - siplog("LOG_INFO", "OUTPUT MSG: '$msg'"); - } + STDOUT->autoflush(1); + print $msg, $terminator; + siplog( "LOG_INFO", "OUTPUT MSG: '$msg'" ); $last_response = $msg; } diff --git a/C4/SIP/Sip/MsgType.pm b/C4/SIP/Sip/MsgType.pm index 4fcd4e486a..f8583ff8ac 100644 --- a/C4/SIP/Sip/MsgType.pm +++ b/C4/SIP/Sip/MsgType.pm @@ -504,12 +504,12 @@ sub handle_patron_status { $ils->check_inst_id( $fields->{ (FID_INST_ID) }, "handle_patron_status" ); $patron = $ils->find_patron( $fields->{ (FID_PATRON_ID) } ); - if ( C4::Context->preference('TrackLastPatronActivityTriggers') ) { + if ( C4::Context->preference('TrackLastPatronActivityTriggers') && $patron ) { my $koha_patron = Koha::Patrons->find($patron->{borrowernumber}); $koha_patron->update_lastseen('connection'); } $resp = build_patron_status( $patron, $lang, $fields, $server ); - $self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} ); + $self->write_msg( $resp, $server ); return (PATRON_STATUS_REQ); } @@ -649,7 +649,7 @@ sub handle_checkout { } } - $self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} ); + $self->write_msg( $resp, $server ); return (CHECKOUT); } @@ -748,7 +748,7 @@ sub handle_checkin { $resp .= maybe_add( FID_SCREEN_MSG, $status->screen_msg, $server ); $resp .= maybe_add( FID_PRINT_LINE, $status->print_line, $server ); - $self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} ); + $self->write_msg( $resp, $server ); return (CHECKIN); } @@ -795,7 +795,7 @@ sub handle_block_patron { } $resp = build_patron_status( $patron, $patron->language, $fields, $server ); - $self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} ); + $self->write_msg( $resp, $server ); return (BLOCK_PATRON); } @@ -836,7 +836,7 @@ sub handle_request_acs_resend { # We haven't sent anything yet, so respond with a # REQUEST_SC_RESEND msg (p. 16) - $self->write_msg( REQUEST_SC_RESEND, undef, $server->{account}->{terminator}, $server->{account}->{encoding} ); + $self->write_msg( REQUEST_SC_RESEND, $server ); } elsif ( ( length($last_response) < 9 ) || substr( $last_response, -9, 2 ) ne 'AY' ) { @@ -850,7 +850,7 @@ sub handle_request_acs_resend { # Cut out the sequence number and checksum, since the old # checksum is wrong for the resent message. my $rebuilt = substr( $last_response, 0, -9 ); - $self->write_msg( $rebuilt, undef, $server->{account}->{terminator}, $server->{account}->{encoding} ); + $self->write_msg( $rebuilt, $server ); } return REQUEST_ACS_RESEND; @@ -932,7 +932,7 @@ sub handle_login { $status = login_core( $server, $uid, $pwd ); } - $self->write_msg( LOGIN_RESP . $status, undef, $server->{account}->{terminator}, $server->{account}->{encoding} ); + $self->write_msg( LOGIN_RESP . $status, $server ); return $status ? LOGIN : ''; } @@ -971,7 +971,7 @@ sub summary_info { my $fid = $summary_map[$summary_type]->{fid}; my $itemlist = &$func( $patron, $start, $end, $server ); - siplog( "LOG_DEBUG", "summary_info: list = (%s)", join( ", ", map{ $_->{barcode} } @{$itemlist} ) ); + siplog( "LOG_DEBUG", "summary_info: list = (%s)", join( ", ", map { $_->{barcode} } @{$itemlist} ) ); foreach my $i ( @{$itemlist} ) { $resp .= add_field( $fid, $i->{barcode}, $server ); } @@ -1101,7 +1101,7 @@ sub handle_patron_info { $resp .= maybe_add( FID_SCREEN_MSG, INVALID_CARD, $server ); } - $self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} ); + $self->write_msg( $resp, $server ); return (PATRON_INFO); } @@ -1128,7 +1128,7 @@ sub handle_end_patron_session { $resp .= maybe_add( FID_SCREEN_MSG, $screen_msg, $server ); $resp .= maybe_add( FID_PRINT_LINE, $print_line, $server ); - $self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} ); + $self->write_msg( $resp, $server ); return (END_PATRON_SESSION); } @@ -1210,7 +1210,7 @@ sub handle_fee_paid { $resp .= maybe_add( FID_SCREEN_MSG, $status->screen_msg, $server ); $resp .= maybe_add( FID_PRINT_LINE, $status->print_line, $server ); - $self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} ); + $self->write_msg( $resp, $server ); return (FEE_PAID); } @@ -1303,7 +1303,7 @@ sub handle_item_information { $resp .= $item->build_custom_field_string( $server ); } - $self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} ); + $self->write_msg( $resp, $server ); return (ITEM_INFORMATION); } @@ -1353,7 +1353,7 @@ sub handle_item_status_update { $resp .= maybe_add( FID_SCREEN_MSG, $status->screen_msg, $server ); $resp .= maybe_add( FID_PRINT_LINE, $status->print_line, $server ); - $self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} ); + $self->write_msg( $resp, $server ); return (ITEM_STATUS_UPDATE); } @@ -1407,7 +1407,7 @@ sub handle_patron_enable { $resp .= add_field( FID_INST_ID, $ils->institution, $server ); - $self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} ); + $self->write_msg( $resp, $server ); return (PATRON_ENABLE); } @@ -1472,7 +1472,7 @@ sub handle_hold { $resp .= maybe_add( FID_SCREEN_MSG, $status->screen_msg, $server ); $resp .= maybe_add( FID_PRINT_LINE, $status->print_line, $server ); - $self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} ); + $self->write_msg( $resp, $server ); return (HOLD); } @@ -1559,7 +1559,7 @@ sub handle_renew { $resp .= maybe_add( FID_SCREEN_MSG, $status->screen_msg, $server ); $resp .= maybe_add( FID_PRINT_LINE, $status->print_line, $server ); - $self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} ); + $self->write_msg( $resp, $server ); return (RENEW); } @@ -1612,7 +1612,7 @@ sub handle_renew_all { $resp .= maybe_add( FID_SCREEN_MSG, $status->screen_msg, $server ); $resp .= maybe_add( FID_PRINT_LINE, $status->print_line, $server ); - $self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} ); + $self->write_msg( $resp, $server ); return (RENEW_ALL); } @@ -1718,7 +1718,7 @@ sub send_acs_status { # Do we want to tell the terminal its location? - $self->write_msg( $msg, undef, $server->{account}->{terminator}, $server->{account}->{encoding} ); + $self->write_msg( $msg, $server ); return 1; } diff --git a/C4/TTParser.pm b/C4/TTParser.pm index 7007fb6604..269d868a77 100644 --- a/C4/TTParser.pm +++ b/C4/TTParser.pm @@ -73,6 +73,26 @@ sub text{ my $line = shift; my $work = shift; # original text my $is_cdata = shift; + # If there is a split template toolkit tag + if ( $work =~ m/^(?:(?!\[%).)*?%\]/s ) { + my @strings = ($&); + my $token; + $work = $'; + while ( $token = pop @tokens ) { + if ( $token->string =~ m/\[%.*?$/s ) { + push @tokens, C4::TmplToken->new( $`, $token->type, $token->line_number, $token->pathname ); + push @strings, $&; + last; + } else { + push @strings, $token->string; + } + } + push @tokens, + C4::TmplToken->new( + join( '', reverse @strings ), C4::TmplTokenType::DIRECTIVE, + $token ? $token->line_number : $line, $self->{filename} + ); + } while($work){ # if there is a template_toolkit tag if( $work =~ m/\[%.*?%\]/ ){ diff --git a/C4/XSLT.pm b/C4/XSLT.pm index 458d732d23..a2134225d8 100644 --- a/C4/XSLT.pm +++ b/C4/XSLT.pm @@ -320,9 +320,9 @@ sub buildKohaItemsNamespace { $status = 'other'; $substatus = 'In transit'; } - elsif ($item->damaged) { - $status = 'other'; - $substatus = "Damaged"; + elsif ( $item->damaged && !C4::Context->preference('AllowHoldsOnDamagedItems') ) { + $status = 'other'; + $substatus = 'Damaged'; } elsif ($item->itemlost) { $status = 'other'; diff --git a/Koha.pm b/Koha.pm index 2e0f5073fb..08eb2a2481 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 = "24.05.05.000"; +$VERSION = "24.05.05.009"; sub version { return $VERSION; diff --git a/Koha/Account/Line.pm b/Koha/Account/Line.pm index 04b920cd5f..2dc5029375 100644 --- a/Koha/Account/Line.pm +++ b/Koha/Account/Line.pm @@ -27,7 +27,6 @@ use Koha::Account::Offsets; use Koha::Database; use Koha::DateUtils qw( dt_from_string ); use Koha::Exceptions::Account; -use Koha::Items; use Koha::Patron::Debarments; use base qw(Koha::Object Koha::Object::Mixin::AdditionalFields); @@ -80,6 +79,7 @@ sub item { my ( $self ) = @_; my $rs = $self->_result->itemnumber; return unless $rs; + require Koha::Item; return Koha::Item->_new_from_dbic( $rs ); } diff --git a/Koha/AdditionalContents.pm b/Koha/AdditionalContents.pm index bbad4869a2..f434fba1a0 100644 --- a/Koha/AdditionalContents.pm +++ b/Koha/AdditionalContents.pm @@ -81,12 +81,13 @@ sub search_for_display { qq|(SELECT COUNT(*) FROM additional_contents_localizations WHERE lang='$lang' AND additional_content_id=me.additional_content_id)=0|; my $search_params; - $search_params->{location} = $params->{location}; - $search_params->{branchcode} = $params->{library_id} ? [ $params->{library_id}, undef ] : undef; - $search_params->{published_on} = { '<=' => \'CAST(NOW() AS DATE)' }; - $search_params->{expirationdate} = [ '-or', { '>=' => \'CAST(NOW() AS DATE)' }, undef ]; + $search_params->{'additional_content.id'} = $params->{id} if $params->{id}; + $search_params->{location} = $params->{location}; + $search_params->{branchcode} = $params->{library_id} ? [ $params->{library_id}, undef ] : undef; + $search_params->{published_on} = { '<=' => \'CAST(NOW() AS DATE)' } unless $params->{id}; + $search_params->{expirationdate} = [ '-or', { '>=' => \'CAST(NOW() AS DATE)' }, undef ] unless $params->{id}; $search_params->{category} = $params->{category} if $params->{category}; - $search_params->{lang} = 'default' if !$lang || $lang eq 'default'; + $search_params->{lang} = 'default' if !$lang || $lang eq 'default'; $search_params->{-or} = [ { 'lang' => $lang }, '-and' => [ 'lang', 'default', \$subquery ] ] if !$search_params->{lang}; diff --git a/Koha/AuthorisedValue.pm b/Koha/AuthorisedValue.pm index f831e4b75b..5669ab6086 100644 --- a/Koha/AuthorisedValue.pm +++ b/Koha/AuthorisedValue.pm @@ -132,6 +132,26 @@ sub is_integer_only { return $self->_result->category->is_integer_only; } +=head3 to_api + + my $json = $av->to_api; + +Overloaded method that returns a JSON representation of the Koha::AuthorisedValue object, +suitable for API output. + +=cut + +sub to_api { + my ( $self, $params ) = @_; + + my $response = $self->SUPER::to_api($params); + my $overrides = {}; + + $overrides->{description} = $self->lib // q{}; + + return { %$response, %$overrides }; +} + =head2 Internal methods =head3 _check_is_integer_only diff --git a/Koha/BackgroundJob/ImportKBARTFile.pm b/Koha/BackgroundJob/ImportKBARTFile.pm index d17dcf502f..890a3c926a 100644 --- a/Koha/BackgroundJob/ImportKBARTFile.pm +++ b/Koha/BackgroundJob/ImportKBARTFile.pm @@ -229,7 +229,7 @@ sub read_file { my $delimiter = $file->{filename} =~ /\.tsv$/ ? "\t" : ","; my $quote_char = $file->{filename} =~ /\.tsv$/ ? "\"" : "\""; - open my $fh, "<", \$file_content or die; + open my $fh, "<", \$file_content or die "Could not open file $file->{filename}: $!"; my $csv = Text::CSV_XS->new( { sep_char => $delimiter, @@ -241,14 +241,16 @@ sub read_file { my $headers_to_check = $csv->getline($fh); my $column_headers = rescue_EBSCO_files($headers_to_check); my $lines = $csv->getline_all( $fh, 0 ); - - my ( $cde, $str, $pos ) = $csv->error_diag(); - my $error = $cde ? "$cde, $str, $pos" : ""; - warn $error if $error; - close($fh); - return ( $column_headers, $lines, $error ); + unless($csv->eof()) { + my ( $cde, $str, $pos ) = $csv->error_diag(); + my $error = $cde ? "$cde, $str, $pos" : ""; + warn $error if $error; + return ( $column_headers, $lines, $error ); + } + + return ( $column_headers, $lines ); } =head3 create_title_hash_from_line_data diff --git a/Koha/BackgroundJob/StageMARCForImport.pm b/Koha/BackgroundJob/StageMARCForImport.pm index 1272378279..e536ded50b 100644 --- a/Koha/BackgroundJob/StageMARCForImport.pm +++ b/Koha/BackgroundJob/StageMARCForImport.pm @@ -144,7 +144,7 @@ sub process { $matcher_code = $matcher->code(); $num_with_matches = BatchFindDuplicates( $batch_id, $matcher, 10, 50, - sub { my $job_progress = shift; $self->progress( $self->progress + $job_progress )->store } ); + sub { my $job_progress = shift; $self->progress( $job_progress )->store } ); SetImportBatchMatcher( $batch_id, $matcher_id ); SetImportBatchOverlayAction( $batch_id, $overlay_action ); SetImportBatchNoMatchAction( $batch_id, $nomatch_action ); diff --git a/Koha/Biblio.pm b/Koha/Biblio.pm index 068356a700..4c7867b6ee 100644 --- a/Koha/Biblio.pm +++ b/Koha/Biblio.pm @@ -52,6 +52,7 @@ use Koha::Item::Transfer::Limits; use Koha::Items; use Koha::Libraries; use Koha::Old::Checkouts; +use Koha::Old::Holds; use Koha::Ratings; use Koha::Recalls; use Koha::RecordProcessor; @@ -462,15 +463,14 @@ the I system preference. sub hidden_in_opac { my ( $self, $params ) = @_; + return 0 unless C4::Context->preference('OpacHiddenItemsHidesRecord'); + my $rules = $params->{rules} // {}; my @items = $self->items->as_list; return 0 unless @items; # Do not hide if there is no item - # Ok, there are items, don't even try the rules unless OpacHiddenItemsHidesRecord - return 0 unless C4::Context->preference('OpacHiddenItemsHidesRecord'); - return !(any { !$_->hidden_in_opac({ rules => $rules }) } @items); } @@ -613,7 +613,8 @@ sub items { my $items_rs = $self->_result->items; - return Koha::Items->_new_from_dbic( $items_rs ) unless $params->{host_items}; + return Koha::Items->_new_from_dbic($items_rs) + unless $params->{host_items} && C4::Context->preference('EasyAnalyticalRecords'); my @itemnumbers = $items_rs->get_column('itemnumber')->all; my $host_itemnumbers = $self->_host_itemnumbers(); @@ -650,7 +651,7 @@ sub host_items { my $host_itemnumbers = $self->_host_itemnumbers; - return Koha::Items->search( { itemnumber => { -in => $host_itemnumbers } } ); + return Koha::Items->search( { "me.itemnumber" => { -in => $host_itemnumbers } } ); } =head3 _host_itemnumbers @@ -707,6 +708,21 @@ sub holds { return Koha::Holds->_new_from_dbic($hold_rs); } +=head3 old_holds + +my $old_holds = $biblio->old_holds(); + +return the historic holds placed on this record + +=cut + +sub old_holds { + my ( $self, $params, $attributes ) = @_; + $attributes->{order_by} = 'priority' unless exists $attributes->{order_by}; + my $old_hold_rs = $self->_result->old_reserves->search( $params, $attributes ); + return Koha::Old::Holds->_new_from_dbic($old_hold_rs); +} + =head3 current_holds my $holds = $biblio->current_holds diff --git a/Koha/Biblio/Metadata/Extractor/MARC.pm b/Koha/Biblio/Metadata/Extractor/MARC.pm index bf030f601b..ceaabf2aa1 100644 --- a/Koha/Biblio/Metadata/Extractor/MARC.pm +++ b/Koha/Biblio/Metadata/Extractor/MARC.pm @@ -27,9 +27,6 @@ use Modern::Perl; use Koha::Exceptions; -use Koha::Biblio::Metadata::Extractor::MARC::MARC21; -use Koha::Biblio::Metadata::Extractor::MARC::UNIMARC; - =head1 API =head2 Class methods @@ -58,6 +55,8 @@ sub new { unless $valid_schemas->{$schema}; my $sub_class = "Koha::Biblio::Metadata::Extractor::MARC::$schema"; + require "Koha/Biblio/Metadata/Extractor/MARC/$schema.pm"; + return $sub_class->new($params); } diff --git a/Koha/EDI.pm b/Koha/EDI.pm index 137a2210c2..7b0eeb3657 100644 --- a/Koha/EDI.pm +++ b/Koha/EDI.pm @@ -45,6 +45,7 @@ use Koha::Plugins; # Adds plugin dirs to @INC use Koha::Plugins::Handler; use Koha::Acquisition::Baskets; use Koha::Acquisition::Booksellers; +use Koha::Util::FrameworkPlugin qw( biblio_008 ); our $VERSION = 1.1; @@ -684,6 +685,10 @@ sub quote_item { if ( !defined $bib ) { $bib = {}; my $bib_record = _create_bib_from_quote( $item, $quote ); + + # Check for and add default 008 as this is a mandatory field + $bib_record = _handle_008_field($bib_record); + ( $bib->{biblionumber}, $bib->{biblioitemnumber} ) = AddBiblio( $bib_record, q{} ); $logger->trace("New biblio added $bib->{biblionumber}"); @@ -1215,6 +1220,17 @@ sub _create_item_from_quote { return $item_hash; } +sub _handle_008_field { + my ($bib_record) = @_; + + if ( !$bib_record->field('008') ) { + my $default008 = biblio_008(); + $bib_record->insert_fields_ordered( MARC::Field->new( '008', $default008 ) ); + } + + return $bib_record; +} + 1; __END__ @@ -1373,6 +1389,14 @@ Koha::EDI Returns the Aqbudget object for the active budget given the passed budget_code or undefined if one does not exist +=head2 _handle_008_field + + bib_record = _handle_008_field($bib_record) + + Checks whether an 008 field exists on the record and adds a default field it does not + + Returns the bib_record + =head1 AUTHOR Colin Campbell diff --git a/Koha/ERM/EUsage/UsageDataProvider.pm b/Koha/ERM/EUsage/UsageDataProvider.pm index e85ee58ce8..ab9f314c80 100644 --- a/Koha/ERM/EUsage/UsageDataProvider.pm +++ b/Koha/ERM/EUsage/UsageDataProvider.pm @@ -180,8 +180,11 @@ sub harvest_sushi { $ua->agent( 'Koha/' . Koha::version() ); my $response = $ua->simple_request($request); + my $result = decode_json( $response->decoded_content ); + if ( $response->code >= 400 ) { - my $result = decode_json( $response->decoded_content ); + + return if $self->_sushi_errors($result); my $message; if ( ref($result) eq 'ARRAY' ) { @@ -199,7 +202,6 @@ sub harvest_sushi { } } - #TODO: May want to add a job error message here? warn sprintf "ERROR - SUSHI service %s returned %s - %s\n", $url, $response->code, $message; if ( $response->code == 404 ) { @@ -208,7 +210,6 @@ sub harvest_sushi { Koha::Exceptions::Authorization::Unauthorized->throw($message); } else { - #TODO: May want to add a job error message here? die sprintf "ERROR requesting SUSHI service\n%s\ncode %s: %s\n", $url, $response->code, $message; @@ -217,12 +218,10 @@ sub harvest_sushi { return; } - my $decoded_response = decode_json( $response->decoded_content ); - - return if $self->_sushi_errors($decoded_response); + return if $self->_sushi_errors($result); # Parse the SUSHI response - my $sushi_counter = Koha::ERM::EUsage::SushiCounter->new( { response => $decoded_response } ); + my $sushi_counter = Koha::ERM::EUsage::SushiCounter->new( { response => $result } ); my $counter_file = $sushi_counter->get_COUNTER_from_SUSHI; return if $self->_counter_file_size_too_large($counter_file); @@ -399,6 +398,7 @@ sub _build_url_query { $url .= '&api_key=' . $self->api_key if $self->api_key; $url .= '&begin_date=' . substr $self->{begin_date}, 0, 7 if $self->{begin_date}; $url .= '&end_date=' . substr $self->{end_date}, 0, 7 if $self->{end_date}; + $url .= '&platform=' . $self->service_platform if $self->service_platform; return $url; } @@ -459,19 +459,24 @@ Additionally, adds background job report message(s) if that is the case sub _sushi_errors { my ( $self, $decoded_response ) = @_; - if ( $decoded_response->{Severity} ) { + my $severity = $decoded_response->{Severity} // $decoded_response->{severity}; + my $message = $decoded_response->{Message} // $decoded_response->{message}; + my $code = $decoded_response->{Code} // $decoded_response->{code}; + + if ($severity) { $self->{job_callbacks}->{add_message_callback}->( { type => 'error', - code => $decoded_response->{Code}, - message => $decoded_response->{Severity} . ' - ' . $decoded_response->{Message}, + code => $code, + message => $severity . ' - ' . $message, } ) if $self->{job_callbacks}; return 1; } - if ( $decoded_response->{Report_Header}->{Exceptions} ) { - foreach my $exception ( @{ $decoded_response->{Report_Header}->{Exceptions} } ) { + my $exceptions = $decoded_response->{Report_Header}->{Exceptions} // $decoded_response->{Exceptions}; + if ($exceptions) { + foreach my $exception ( @{$exceptions} ) { $self->{job_callbacks}->{add_message_callback}->( { type => 'error', @@ -483,7 +488,7 @@ sub _sushi_errors { return 1; } - if ( scalar @{ $decoded_response->{Report_Items} } == 0 ) { + if ( $decoded_response->{Report_Items} && scalar @{ $decoded_response->{Report_Items} } == 0 ) { $self->{job_callbacks}->{add_message_callback}->( { type => 'error', diff --git a/Koha/ERM/Providers/EBSCO.pm b/Koha/ERM/Providers/EBSCO.pm index c0904cb225..5e3aa377ef 100644 --- a/Koha/ERM/Providers/EBSCO.pm +++ b/Koha/ERM/Providers/EBSCO.pm @@ -210,10 +210,10 @@ sub embed { sub build_query_pagination { my ( $self, $params ) = @_; - my $per_page = $params->{per_page} + my $per_page = $params->{_per_page} // C4::Context->preference('RESTdefaultPageSize') // 20; if ( $per_page == -1 || $per_page > 100 ) { $per_page = 100; } - my $page = $params->{page} || 1; + my $page = $params->{_page} || 1; return ( $per_page, $page ); } diff --git a/Koha/Hold.pm b/Koha/Hold.pm index 12109ad573..27e2447eae 100644 --- a/Koha/Hold.pm +++ b/Koha/Hold.pm @@ -34,7 +34,6 @@ use Koha::Biblios; use Koha::Hold::CancellationRequests; use Koha::Items; use Koha::Libraries; -use Koha::Old::Holds; use Koha::Calendar; use Koha::Plugins; @@ -1014,6 +1013,7 @@ Move a hold to the old_reserve table following the same pattern as Koha::Patron- sub _move_to_old { my ($self) = @_; my $hold_infos = $self->unblessed; + require Koha::Old::Hold; return Koha::Old::Hold->new( $hold_infos )->store; } @@ -1026,25 +1026,26 @@ on the API. sub to_api_mapping { return { - reserve_id => 'hold_id', - borrowernumber => 'patron_id', - reservedate => 'hold_date', - biblionumber => 'biblio_id', - branchcode => 'pickup_library_id', - notificationdate => undef, - reminderdate => undef, - cancellationdate => 'cancellation_date', - reservenotes => 'notes', - found => 'status', - itemnumber => 'item_id', - waitingdate => 'waiting_date', - expirationdate => 'expiration_date', + reserve_id => 'hold_id', + borrowernumber => 'patron_id', + reservedate => 'hold_date', + biblionumber => 'biblio_id', + deleted_biblionumber => 'deleted_biblio_id', + branchcode => 'pickup_library_id', + notificationdate => undef, + reminderdate => undef, + cancellationdate => 'cancellation_date', + reservenotes => 'notes', + found => 'status', + itemnumber => 'item_id', + waitingdate => 'waiting_date', + expirationdate => 'expiration_date', patron_expiration_date => undef, - lowestPriority => 'lowest_priority', - suspend => 'suspended', - suspend_until => 'suspended_until', - itemtype => 'item_type', - item_level_hold => 'item_level', + lowestPriority => 'lowest_priority', + suspend => 'suspended', + suspend_until => 'suspended_until', + itemtype => 'item_type', + item_level_hold => 'item_level', }; } diff --git a/Koha/ILL/Request.pm b/Koha/ILL/Request.pm index beb185e078..6290d5be20 100644 --- a/Koha/ILL/Request.pm +++ b/Koha/ILL/Request.pm @@ -401,20 +401,23 @@ sub status { my $backend_plugin = $self->get_backend_plugin($backend_name); -Returns the installed I corresponding to the given backend_id +Returns the installed I corresponding to the given backend_id or undef if no plugin is found =cut sub get_backend_plugin { my ( $self, $backend_id ) = @_; - my @backend_plugins = Koha::Plugins->new()->GetPlugins( + my $koha_plugins = Koha::Plugins->new(); + my @backend_plugins = $koha_plugins + ? Koha::Plugins->new()->GetPlugins( { method => 'ill_backend', metadata => { name => $backend_id }, all => 1, } - ); + ) + : (); return $backend_plugins[0]; } diff --git a/Koha/ILL/Request/Config.pm b/Koha/ILL/Request/Config.pm index 111317804c..815f63309f 100644 --- a/Koha/ILL/Request/Config.pm +++ b/Koha/ILL/Request/Config.pm @@ -113,14 +113,17 @@ Returns a list of names for all the installed ILL backend plugins. =cut sub get_backend_plugin_names { - my ( $self ) = @_; + my ($self) = @_; - my @backend_plugins = Koha::Plugins->new()->GetPlugins( + my $koha_plugins = Koha::Plugins->new(); + my @backend_plugins = $koha_plugins + ? $koha_plugins->GetPlugins( { method => 'ill_backend', all => 1 } - ); + ) + : (); return map { $_->{metadata}->{name} } @backend_plugins; } diff --git a/Koha/Import/Record.pm b/Koha/Import/Record.pm index ea238e6254..14fab57e54 100644 --- a/Koha/Import/Record.pm +++ b/Koha/Import/Record.pm @@ -56,7 +56,7 @@ sub get_marc_record { $format = 'UNIMARCAUTH'; } - my $record = MARC::Record->new_from_xml($self->marcxml, $self->encoding, $format); + my $record = MARC::Record->new_from_xml( $self->marcxml, 'UTF-8', $format ); return $record; } diff --git a/Koha/Item.pm b/Koha/Item.pm index 729f4ba761..7590dbd34d 100644 --- a/Koha/Item.pm +++ b/Koha/Item.pm @@ -920,7 +920,7 @@ sub hidden_in_opac { foreach my $field ( keys %{$rules} ) { - if ( any { $self->$field eq $_ } @{ $rules->{$field} } ) { + if ( any { defined $self->$field && $self->$field eq $_ } @{ $rules->{$field} } ) { $hidden_in_opac = 1; last; } diff --git a/Koha/Middleware/CSRF.pm b/Koha/Middleware/CSRF.pm index 58e75c948e..811c212386 100644 --- a/Koha/Middleware/CSRF.pm +++ b/Koha/Middleware/CSRF.pm @@ -44,10 +44,19 @@ sub call { my $request_method = $req->method // q{}; my $uri = $req->uri // q{}; my $referer = $req->referer // q{No referer}; + my $request_path = $req->path // q{}; + + my %path_exceptions = ( + '/ilsdi.pl' => 1, + ); #NOTE: Ignore ErrorDocument requests for CSRF if ( $env->{'psgix.errordocument.SCRIPT_NAME'} ) { return $self->app->($env); + } elsif ( $path_exceptions{$request_path} ) { + + #NOTE: Ignore path exceptions for CSRF + return $self->app->($env); } my ($error); diff --git a/Koha/Number/Price.pm b/Koha/Number/Price.pm index e9a6aa748e..a0f847d495 100644 --- a/Koha/Number/Price.pm +++ b/Koha/Number/Price.pm @@ -19,6 +19,7 @@ package Koha::Number::Price; use Modern::Perl; +use Math::BigFloat; use Number::Format; use C4::Context; use Koha::Acquisition::Currencies; @@ -83,12 +84,7 @@ sub round { my $format_params = $self->_format_params; - # To avoid the system to crash, we will not format big number - # We divide per 100 because we want to keep the default DECIMAL_DIGITS (2) - # error - round() overflow. Try smaller precision or use Math::BigFloat - return $self->value if $self->value > Number::Format::MAX_INT/100; - - return Number::Format->new(%$format_params)->round($self->value); + return Number::Format->new(%$format_params)->round( Math::BigFloat->new( $self->value ) )->bdstr(); } sub _format_params { diff --git a/Koha/Object/Limit/Library.pm b/Koha/Object/Limit/Library.pm index cb2f29aa28..85907394e9 100644 --- a/Koha/Object/Limit/Library.pm +++ b/Koha/Object/Limit/Library.pm @@ -19,7 +19,6 @@ use Modern::Perl; use Koha::Database; use Koha::Exceptions; -use Koha::Libraries; use Try::Tiny qw( catch try ); @@ -87,6 +86,8 @@ sub get_library_limits { return unless @branchcodes; + require Koha::Libraries; + my $filter = [ map { { branchcode => $_ } } @branchcodes ]; my $libraries = Koha::Libraries->search( $filter ); diff --git a/Koha/Objects.pm b/Koha/Objects.pm index a59e5d5712..3bd1e77886 100644 --- a/Koha/Objects.pm +++ b/Koha/Objects.pm @@ -167,17 +167,19 @@ sub search_related { =cut sub delete { - my ($self) = @_; + my ( $self, $params ) = @_; if ( Class::Inspector->function_exists( $self->object_class, 'delete' ) ) { my $objects_deleted; - $self->_resultset->result_source->schema->txn_do( sub { - $self->reset; # If we iterated already over the set - while ( my $o = $self->next ) { - $o->delete; - $objects_deleted++; + $self->_resultset->result_source->schema->txn_do( + sub { + $self->reset; # If we iterated already over the set + while ( my $o = $self->next ) { + $o->delete($params); + $objects_deleted++; + } } - }); + ); return $objects_deleted; } diff --git a/Koha/Patron.pm b/Koha/Patron.pm index 70cbe3ab7f..0483b88e16 100644 --- a/Koha/Patron.pm +++ b/Koha/Patron.pm @@ -20,7 +20,7 @@ package Koha::Patron; use Modern::Perl; -use List::MoreUtils qw( any uniq ); +use List::MoreUtils qw( any none uniq ); use JSON qw( to_json ); use Unicode::Normalize qw( NFKD ); use Try::Tiny; @@ -315,7 +315,7 @@ sub store { } foreach my $guarantor (@$guarantors) { - if ( $guarantor->is_child or $guarantor->category->can_be_guarantee ) { + if ( $guarantor->is_child ) { Koha::Exceptions::Patron::Relationship::InvalidRelationship->throw( invalid_guarantor => 1 ); } } @@ -372,7 +372,7 @@ sub store { } foreach my $guarantor (@$guarantors) { - if ( $guarantor->is_child or $guarantor->category->can_be_guarantee ) { + if ( $guarantor->is_child ) { Koha::Exceptions::Patron::Relationship::InvalidRelationship->throw( invalid_guarantor => 1 ); } } @@ -443,7 +443,7 @@ sub delete { Koha::Exceptions::Patron::FailedDeleteAnonymousPatron->throw() if $anonymous_patron && $self->id eq $anonymous_patron; # Check if patron is protected - Koha::Exceptions::Patron::FailedDeleteProtectedPatron->throw() if $self->protected == 1; + Koha::Exceptions::Patron::FailedDeleteProtectedPatron->throw() if defined $self->protected && $self->protected == 1; $self->_result->result_source->schema->txn_do( sub { @@ -499,7 +499,7 @@ Returns a Koha::Library object representing the patron's home library. sub library { my ( $self ) = @_; - return Koha::Library->_new_from_dbic($self->_result->branchcode); + return Koha::Library->_new_from_dbic($self->_result->library); } =head3 sms_provider @@ -533,6 +533,18 @@ sub guarantor_relationships { return Koha::Patron::Relationships->search( { guarantee_id => $self->id } ); } +=head3 is_guarantee + +Returns true if the patron has a guarantor. + +=cut + +sub is_guarantee { + my ($self) = @_; + return $self->guarantor_relationships()->count(); +} + + =head3 guarantee_relationships Returns Koha::Patron::Relationships object for this patron's guarantors @@ -557,6 +569,18 @@ sub guarantee_relationships { ); } +=head3 is_guarantor + +Returns true if the patron is a guarantor. + +=cut + +sub is_guarantor { + my ($self) = @_; + return $self->guarantee_relationships()->count(); +} + + =head3 relationships_debt Returns the amount owed by the patron's guarantors *and* the other guarantees of those guarantors @@ -1527,6 +1551,7 @@ sub get_age { my $date_of_birth = dt_from_string( $self->dateofbirth, undef, 'floating' ); my $today = dt_from_string(undef, undef, 'floating')->truncate( to => 'day' ); + return 0 unless $date_of_birth; return $today->subtract_datetime( $date_of_birth )->years; } @@ -1584,6 +1609,7 @@ Return all the historical holds for this patron sub old_holds { my ($self) = @_; my $old_holds_rs = $self->_result->old_reserves->search( {}, { order_by => 'reservedate' } ); + require Koha::Old::Holds; return Koha::Old::Holds->_new_from_dbic($old_holds_rs); } @@ -1629,23 +1655,27 @@ sub return_claims { =head3 notice_email_address - my $email = $patron->notice_email_address; + my $email = $patron->notice_email_address; Return the email address of patron used for notices. Returns the empty string if no email address. =cut -sub notice_email_address{ - my ( $self ) = @_; +sub notice_email_address { + my ($self) = @_; my $which_address = C4::Context->preference("EmailFieldPrimary"); - # if syspref is set to 'first valid' (value == OFF), look up email address - if ( $which_address eq 'OFF' ) { - return $self->first_valid_email_address; + if ( $which_address && ( none { $_ eq $which_address } qw{email emailpro B_email cardnumber MULTI} ) ) { + warn "Invalid value for EmailFieldPrimary ($which_address)"; + $which_address = undef; } + # if syspref is set to 'first valid', look up email address + return $self->first_valid_email_address + unless $which_address; + # if syspref is set to 'selected addresses' (value == MULTI), look up email addresses if ( $which_address eq 'MULTI' ) { my @addresses; @@ -1654,11 +1684,10 @@ sub notice_email_address{ my $email_address = $self->$email_field; push @addresses, $email_address if $email_address; } - return join(",",@addresses); + return join( ",", @addresses ); } return $self->$which_address || ''; - } =head3 first_valid_email_address @@ -2179,17 +2208,22 @@ sub extended_attributes { } # Check globally mandatory types - my @required_attribute_types = - Koha::Patron::Attribute::Types->search( - { - mandatory => 1, - category_code => [ undef, $self->categorycode ], - 'borrower_attribute_types_branches.b_branchcode' => - undef, - }, - { join => 'borrower_attribute_types_branches' } - )->get_column('code'); - for my $type ( @required_attribute_types ) { + my $interface = C4::Context->interface; + my $params = { + mandatory => 1, + category_code => [ undef, $self->categorycode ], + 'borrower_attribute_types_branches.b_branchcode' => undef, + }; + + if ( $interface eq 'opac' ) { + $params->{opac_editable} = 1; + } + + my @required_attribute_types = Koha::Patron::Attribute::Types->search( + $params, + { join => 'borrower_attribute_types_branches' } + )->get_column('code'); + for my $type (@required_attribute_types) { Koha::Exceptions::Patron::MissingMandatoryExtendedAttribute->throw( type => $type, ) if !$new_types->{$type}; diff --git a/Koha/Patron/Attribute.pm b/Koha/Patron/Attribute.pm index 5fc1b9111d..93b25ece02 100644 --- a/Koha/Patron/Attribute.pm +++ b/Koha/Patron/Attribute.pm @@ -59,6 +59,11 @@ sub store { Koha::Exceptions::Patron::Attribute::InvalidAttributeValue->throw( attribute => $self ) unless $self->value_ok(); + C4::Context->dbh->do( + "UPDATE borrowers SET updated_on = NOW() WHERE borrowernumber = ?", undef, + $self->borrowernumber + ); + return $self->SUPER::store(); } diff --git a/Koha/REST/Plugin/Query.pm b/Koha/REST/Plugin/Query.pm index 01fa0e8cd4..c8ba09e8d4 100644 --- a/Koha/REST/Plugin/Query.pm +++ b/Koha/REST/Plugin/Query.pm @@ -512,7 +512,7 @@ sub _validate_operator { my ($operator) = @_; my %allowed_operators = map { $_ => 1 } - qw(= != < > <= >= -in -ident -bool -not_bool -or like -like -not_like -between -not_between -not -and -regexp); + qw(= != < > <= >= -in -ident -bool -not_bool -or like -like -not_like -between -not_between -not -and -regexp -not_in); Koha::Exceptions::REST::Query::InvalidOperator->throw( operator => $operator ) unless exists $allowed_operators{$operator}; return; diff --git a/Koha/REST/V1/AuthorisedValueCategories.pm b/Koha/REST/V1/AuthorisedValueCategories.pm index 3a7872f6de..f3245115c1 100644 --- a/Koha/REST/V1/AuthorisedValueCategories.pm +++ b/Koha/REST/V1/AuthorisedValueCategories.pm @@ -36,8 +36,9 @@ sub list { my $c = shift->openapi->valid_input or return; return try { - my $authorised_value_categories_set = Koha::AuthorisedValueCategories->new; - my $authorised_value_categories = $c->objects->search( $authorised_value_categories_set ); + my $authorised_value_categories_set = + Koha::AuthorisedValueCategories->search( {}, { order_by => 'category_name' } ); + my $authorised_value_categories = $c->objects->search($authorised_value_categories_set); return $c->render( status => 200, openapi => $authorised_value_categories ); } catch { diff --git a/Koha/REST/V1/Checkouts.pm b/Koha/REST/V1/Checkouts.pm index c1b874f35d..301369a45c 100644 --- a/Koha/REST/V1/Checkouts.pm +++ b/Koha/REST/V1/Checkouts.pm @@ -120,7 +120,7 @@ sub _check_availability { # Upgrade some confirmations to blockers my @should_block = - qw/TOO_MANY ISSUED_TO_ANOTHER RESERVED RESERVED_WAITING TRANSFERRED PROCESSING AGE_RESTRICTION/; + qw/TOO_MANY ISSUED_TO_ANOTHER RESERVED RESERVE_WAITING TRANSFERRED PROCESSING AGE_RESTRICTION/; for my $block (@should_block) { if ( exists( $confirmation->{$block} ) ) { $impossible->{$block} = $confirmation->{$block}; diff --git a/Koha/REST/V1/ERM/EHoldings/Packages/EBSCO.pm b/Koha/REST/V1/ERM/EHoldings/Packages/EBSCO.pm index b4a59c4128..5f92ba2a6a 100644 --- a/Koha/REST/V1/ERM/EHoldings/Packages/EBSCO.pm +++ b/Koha/REST/V1/ERM/EHoldings/Packages/EBSCO.pm @@ -35,12 +35,7 @@ sub list { my $result = $ebsco->request( GET => '/packages' . $params ); my $base_total = $result->{totalResults}; - my ( $per_page, $page ) = $ebsco->build_query_pagination( - { - per_page => $c->stash('koha.pagination.per_page'), - page => $c->stash('koha.pagination.page'), - } - ); + my ( $per_page, $page ) = $ebsco->build_query_pagination( $c->req->params->to_hash ); my $additional_params = $ebsco->build_additional_params( $c->req->params->to_hash ); diff --git a/Koha/REST/V1/ERM/EHoldings/Resources/EBSCO.pm b/Koha/REST/V1/ERM/EHoldings/Resources/EBSCO.pm index 39ba226752..e8f3c44d20 100644 --- a/Koha/REST/V1/ERM/EHoldings/Resources/EBSCO.pm +++ b/Koha/REST/V1/ERM/EHoldings/Resources/EBSCO.pm @@ -73,12 +73,7 @@ sub list { my $base_total = $result->{totalResults}; - my ( $per_page, $page ) = $ebsco->build_query_pagination( - { - per_page => $c->stash('koha.pagination.per_page'), - page => $c->stash('koha.pagination.page'), - } - ); + my ( $per_page, $page ) = $ebsco->build_query_pagination( $c->req->params->to_hash ); my $additional_params = $ebsco->build_additional_params( $c->req->params->to_hash ); my $searchfield = 'titlename'; diff --git a/Koha/REST/V1/ERM/EHoldings/Titles/EBSCO.pm b/Koha/REST/V1/ERM/EHoldings/Titles/EBSCO.pm index cacc1c84b5..d569e75ddc 100644 --- a/Koha/REST/V1/ERM/EHoldings/Titles/EBSCO.pm +++ b/Koha/REST/V1/ERM/EHoldings/Titles/EBSCO.pm @@ -41,12 +41,7 @@ sub list { my $ebsco = Koha::ERM::Providers::EBSCO->new; # We cannot get base_total as a search kw is required by the API - my ( $per_page, $page ) = $ebsco->build_query_pagination( - { - per_page => $c->stash('koha.pagination.per_page'), - page => $c->stash('koha.pagination.page'), - } - ); + my ( $per_page, $page ) = $ebsco->build_query_pagination( $c->req->params->to_hash ); my $additional_params = $ebsco->build_additional_params( $c->req->params->to_hash ); diff --git a/Koha/REST/V1/Patrons/Account.pm b/Koha/REST/V1/Patrons/Account.pm index ab8676d98d..b80217b4bb 100644 --- a/Koha/REST/V1/Patrons/Account.pm +++ b/Koha/REST/V1/Patrons/Account.pm @@ -207,14 +207,14 @@ sub add_debit { my $c = shift->openapi->valid_input or return; my $patron = Koha::Patrons->find( $c->param('patron_id') ); + my $user = $c->stash('koha.user'); return $c->render_resource_not_found("Patron") - unless $patron; + unless $patron; return try { my $data = - Koha::Account::Debit->new_from_api( $c->req->json ) - ->unblessed; + Koha::Account::Debit->new_from_api( $c->req->json )->unblessed; $data->{library_id} = delete $data->{branchcode}; $data->{type} = delete $data->{debit_type_code}; @@ -223,11 +223,10 @@ sub add_debit { $data->{transaction_type} = delete $data->{payment_type}; $data->{interface} = 'api' ; # Should this always be API, or should we allow the API consumer to choose? - $data->{user_id} = $patron->borrowernumber - ; # Should this be API user OR staff the API may be acting on behalf of? + $data->{user_id} = delete $data->{manager_id} || $user->id; my $debit = $patron->account->add_debit($data); - $debit = Koha::Account::Debit->_new_from_dbic($debit->{_result}); + $debit = Koha::Account::Debit->_new_from_dbic( $debit->{_result} ); $c->res->headers->location( $c->req->url->to_string . '/' . $debit->id ); @@ -248,13 +247,13 @@ sub add_debit { } elsif ( $_->isa('Koha::Exceptions::Account::AmountNotPositive') ) { return $c->render( - status => 400, + status => 400, openapi => { error => $_->description } ); } elsif ( $_->isa('Koha::Exceptions::Account::UnrecognisedType') ) { return $c->render( - status => 400, + status => 400, openapi => { error => $_->description } ); } diff --git a/Koha/REST/V1/RecordSources.pm b/Koha/REST/V1/RecordSources.pm index 522b6943d3..46ce01b50f 100644 --- a/Koha/REST/V1/RecordSources.pm +++ b/Koha/REST/V1/RecordSources.pm @@ -55,12 +55,8 @@ sub get { return try { my $source = $c->objects->find( Koha::RecordSources->new, $c->param('record_source_id') ); - unless ($source) { - return $c->render( - status => 404, - openapi => { error => "Object not found" } - ); - } + return $c->render_resource_not_found("Record source") + unless $source; return $c->render( status => 200, openapi => $source ); } catch { @@ -97,12 +93,8 @@ sub update { my $source = $c->objects->find_rs( Koha::RecordSources->new, $c->param('record_source_id') ); - unless ($source) { - return $c->render( - status => 404, - openapi => { error => "Object not found" } - ); - } + return $c->render_resource_not_found("Record source") + unless $source; return try { $source->set_from_api( $c->req->json )->store; @@ -122,19 +114,12 @@ sub delete { my $source = $c->objects->find_rs( Koha::RecordSources->new, $c->param('record_source_id') ); - unless ($source) { - return $c->render( - status => 404, - openapi => { error => "Object not found" } - ); - } + return $c->render_resource_not_found("Record source") + unless $source; return try { $source->delete; - return $c->render( - status => 204, - openapi => q{} - ); + return $c->render_resource_deleted; } catch { $c->unhandled_exception($_); }; diff --git a/Koha/Schema/Result/Borrower.pm b/Koha/Schema/Result/Borrower.pm index bf8ba36030..fddaf77201 100644 --- a/Koha/Schema/Result/Borrower.pm +++ b/Koha/Schema/Result/Borrower.pm @@ -2191,6 +2191,13 @@ __PACKAGE__->many_to_many("permissions", "user_permissions", "permission"); # Created by DBIx::Class::Schema::Loader v0.07051 @ 2024-05-02 11:36:36 # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:jUOMoSonNmA3KwtZKVxqOA +__PACKAGE__->belongs_to( + "library", + "Koha::Schema::Result::Branch", + { branchcode => "branchcode" }, + { is_deferrable => 1, on_delete => "RESTRICT", on_update => "RESTRICT" }, +); + __PACKAGE__->has_many( "restrictions", "Koha::Schema::Result::BorrowerDebarment", diff --git a/Koha/Schema/Result/Deleteditem.pm b/Koha/Schema/Result/Deleteditem.pm index 49a47984c8..118b225121 100644 --- a/Koha/Schema/Result/Deleteditem.pm +++ b/Koha/Schema/Result/Deleteditem.pm @@ -61,7 +61,7 @@ item barcode (MARC21 952$p) default_value: 0 is_nullable: 0 -boolean value defining whether this item is available for bookings or not +boolean value defining whether this this item is available for bookings or not =head2 dateaccessioned diff --git a/Koha/Schema/Result/ErmAgreement.pm b/Koha/Schema/Result/ErmAgreement.pm index b2b97e4f3e..9f80140770 100644 --- a/Koha/Schema/Result/ErmAgreement.pm +++ b/Koha/Schema/Result/ErmAgreement.pm @@ -88,9 +88,8 @@ priority of the renewal =head2 license_info - data_type: 'varchar' + data_type: 'mediumtext' is_nullable: 1 - size: 80 info about the license @@ -114,7 +113,7 @@ __PACKAGE__->add_columns( "renewal_priority", { data_type => "varchar", is_nullable => 1, size => 80 }, "license_info", - { data_type => "varchar", is_nullable => 1, size => 80 }, + { data_type => "mediumtext", is_nullable => 1 }, ); =head1 PRIMARY KEY @@ -267,8 +266,8 @@ Composing rels: L -> package __PACKAGE__->many_to_many("packages", "erm_eholdings_packages_agreements", "package"); -# Created by DBIx::Class::Schema::Loader v0.07049 @ 2022-11-11 11:52:09 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:N93LnvdKirtuV6BSrTGzVg +# Created by DBIx::Class::Schema::Loader v0.07051 @ 2024-12-17 23:37:27 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:lc0DnoQ5ai9sVBjczw6FdQ __PACKAGE__->has_many( "user_roles", diff --git a/Koha/Schema/Result/ErmUsageDataProvider.pm b/Koha/Schema/Result/ErmUsageDataProvider.pm index a65fa28789..0a5251cf74 100644 --- a/Koha/Schema/Result/ErmUsageDataProvider.pm +++ b/Koha/Schema/Result/ErmUsageDataProvider.pm @@ -142,6 +142,14 @@ requestor email report types provided by the harvester +=head2 service_platform + + data_type: 'varchar' + is_nullable: 1 + size: 80 + +platform if provider requires it + =cut __PACKAGE__->add_columns( @@ -175,6 +183,8 @@ __PACKAGE__->add_columns( { data_type => "varchar", is_nullable => 1, size => 80 }, "report_types", { data_type => "varchar", is_nullable => 1, size => 255 }, + "service_platform", + { data_type => "varchar", is_nullable => 1, size => 80 }, ); =head1 PRIMARY KEY @@ -328,8 +338,8 @@ __PACKAGE__->has_many( ); -# Created by DBIx::Class::Schema::Loader v0.07049 @ 2023-10-11 10:09:06 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:MSvyv/Abt3S3fqZF21v/7w +# Created by DBIx::Class::Schema::Loader v0.07051 @ 2024-12-05 19:06:48 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:VzC6luzfNA1QBZ7slRs6OQ # __PACKAGE__->add_columns( # '+active' => { is_boolean => 1 } diff --git a/Koha/Schema/Result/Item.pm b/Koha/Schema/Result/Item.pm index 1b3612b8ee..dcbd2275a8 100644 --- a/Koha/Schema/Result/Item.pm +++ b/Koha/Schema/Result/Item.pm @@ -63,7 +63,7 @@ item barcode (MARC21 952$p) default_value: 0 is_nullable: 0 -boolean value defining whether this item is available for bookings or not +boolean value defining whether this this item is available for bookings or not =head2 dateaccessioned diff --git a/Koha/Schema/Result/OldReserve.pm b/Koha/Schema/Result/OldReserve.pm index cbe46e7881..422b60aeac 100644 --- a/Koha/Schema/Result/OldReserve.pm +++ b/Koha/Schema/Result/OldReserve.pm @@ -54,6 +54,13 @@ the date the hold was places foreign key from the biblio table defining which bib record this hold is on +=head2 deleted_biblionumber + + data_type: 'integer' + is_nullable: 1 + +links the hold to the deleted bibliographic record (deletedbiblio.biblionumber) + =head2 item_group_id data_type: 'integer' @@ -235,6 +242,8 @@ __PACKAGE__->add_columns( { data_type => "date", datetime_undef_if_invalid => 1, is_nullable => 1 }, "biblionumber", { data_type => "integer", is_foreign_key => 1, is_nullable => 1 }, + "deleted_biblionumber", + { data_type => "integer", is_nullable => 1 }, "item_group_id", { data_type => "integer", is_foreign_key => 1, is_nullable => 1 }, "branchcode", @@ -428,8 +437,8 @@ __PACKAGE__->belongs_to( ); -# Created by DBIx::Class::Schema::Loader v0.07049 @ 2024-04-05 06:44:57 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:SQp2OEYb3im1x3A+W0h37w +# Created by DBIx::Class::Schema::Loader v0.07051 @ 2024-12-05 19:06:48 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:7mO1W8tdYtEk7pijJuxsMA __PACKAGE__->belongs_to( "item", diff --git a/Koha/Schema/Result/Reserve.pm b/Koha/Schema/Result/Reserve.pm index a91c14c9a0..da25403fcf 100644 --- a/Koha/Schema/Result/Reserve.pm +++ b/Koha/Schema/Result/Reserve.pm @@ -57,6 +57,13 @@ the date the hold was placed foreign key from the biblio table defining which bib record this hold is on +=head2 deleted_biblionumber + + data_type: 'integer' + is_nullable: 1 + +links the hold to the deleted bibliographic record (deletedbiblio.biblionumber) + =head2 item_group_id data_type: 'integer' @@ -243,6 +250,8 @@ __PACKAGE__->add_columns( is_foreign_key => 1, is_nullable => 0, }, + "deleted_biblionumber", + { data_type => "integer", is_nullable => 1 }, "item_group_id", { data_type => "integer", is_foreign_key => 1, is_nullable => 1 }, "branchcode", @@ -456,8 +465,8 @@ __PACKAGE__->belongs_to( ); -# Created by DBIx::Class::Schema::Loader v0.07049 @ 2023-11-01 18:21:38 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:6BAjuPSwjtyWJaJN9fcOtg +# Created by DBIx::Class::Schema::Loader v0.07051 @ 2024-12-05 19:06:48 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:OU6N7F+5LfbGfkhJMv53GA __PACKAGE__->belongs_to( "item", diff --git a/Koha/SearchEngine/Elasticsearch.pm b/Koha/SearchEngine/Elasticsearch.pm index e27036bc1a..79522b4f27 100644 --- a/Koha/SearchEngine/Elasticsearch.pm +++ b/Koha/SearchEngine/Elasticsearch.pm @@ -790,7 +790,20 @@ sub marc_records_to_documents { local $SIG{__WARN__} = sub { push @warnings, $_[0]; }; - $record_document->{'marc_data'} = encode_base64(encode('UTF-8', $record->as_usmarc())); + my $usmarc_record = $record->as_usmarc(); + + #NOTE: Try to round-trip the record to prove it will work for retrieval after searching + my $decoded_usmarc_record = MARC::Record->new_from_usmarc($usmarc_record); + if ( $decoded_usmarc_record->warnings() ) { + + #NOTE: We override the warnings since they're many and misleading + @warnings = ( + "Warnings encountered while roundtripping a MARC record to/from USMARC. Failing over to MARCXML.", + ); + } + + my $marc_data = encode_base64( encode( 'UTF-8', $usmarc_record ) ); + $record_document->{'marc_data'} = $marc_data; } if (@warnings) { # Suppress warnings if record length exceeded diff --git a/Koha/SearchEngine/Elasticsearch/Search.pm b/Koha/SearchEngine/Elasticsearch/Search.pm index f4a316345a..f7fd99aaf5 100644 --- a/Koha/SearchEngine/Elasticsearch/Search.pm +++ b/Koha/SearchEngine/Elasticsearch/Search.pm @@ -248,6 +248,20 @@ sub search_auth_compat { $result{authtype} = $authtype ? $authtype->authtypetext : $authtypecode; $result{reported_tag} = $reported_tag; + if ( C4::Context->preference('ShowHeadingUse') ) { + # checking valid heading use + my $f008 = $marc->field('008'); + if ($f008) { + my $pos14to16 = substr( $f008->data, 14, 3 ); + my $main = substr( $pos14to16, 0, 1 ); + $result{main} = 1 if $main eq 'a'; + my $subject = substr( $pos14to16, 1, 1 ); + $result{subject} = 1 if $subject eq 'a'; + my $series = substr( $pos14to16, 2, 1 ); + $result{series} = 1 if $series eq 'a'; + } + } + # Reimplementing BuildSummary is out of scope because it'll be hard $result{summary} = C4::AuthoritiesMarc::BuildSummary( $marc, $result{authid}, @@ -497,7 +511,7 @@ sub _convert_facets { push @{ $facet->{facets} }, { facet_count => $c, facet_link_value => $t, - facet_title_value => $t . " ($c)", + facet_title_value => $t, facet_label_value => $label, # TODO either truncate this, # or make the template do it like it should anyway type_link_value => $type, diff --git a/Koha/SearchFilter.pm b/Koha/SearchFilter.pm index 3683a89b28..9694c1e31c 100644 --- a/Koha/SearchFilter.pm +++ b/Koha/SearchFilter.pm @@ -51,7 +51,7 @@ sub expand_filter { my $operands = $query->{operands}; my $indexes = $query->{indexes}; - my $query_limit; + my $query_limit = "("; for( my $i = 0; $i < scalar @$operands; $i++ ){ next unless @$operands[$i]; my $index = @$indexes[$i] ? @$indexes[$i] . "=" : ""; @@ -61,6 +61,7 @@ sub expand_filter { my $limit = $operator . $index . $query; $query_limit .= $limit; } + $query_limit .= ")"; return ($limits, $query_limit); } diff --git a/Koha/Statistic.pm b/Koha/Statistic.pm index 14f299569f..4e981c31c2 100644 --- a/Koha/Statistic.pm +++ b/Koha/Statistic.pm @@ -150,7 +150,14 @@ sub pseudonymize { my ($self) = @_; return unless ( $self->borrowernumber && grep { $_ eq $self->type } qw(renew issue return onsite_checkout) ); - Koha::BackgroundJob::PseudonymizeStatistic->new->enqueue( { statistic => $self->unblessed } ); + + # FIXME When getting the object from svc/renewal we get a DateTime object + # normally we just fetch from DB to clear this, but statistics has no primary key + # so we just force it to string context + my $unblessed = $self->unblessed; + $unblessed->{datetime} = $unblessed->{datetime} . ""; + + Koha::BackgroundJob::PseudonymizeStatistic->new->enqueue( { statistic => $unblessed } ); } diff --git a/Koha/Template/Plugin/AdditionalContents.pm b/Koha/Template/Plugin/AdditionalContents.pm index a44de966dc..b919ecf682 100644 --- a/Koha/Template/Plugin/AdditionalContents.pm +++ b/Koha/Template/Plugin/AdditionalContents.pm @@ -40,10 +40,11 @@ sub get { my $content = Koha::AdditionalContents->search_for_display( { - category => $category, - location => $location, - lang => $lang, + category => $category, + location => $location, + lang => $lang, ( $library ? ( library_id => $library ) : () ), + ( $id ? ( id => $id ) : () ), } ); diff --git a/Koha/Template/Plugin/SafeURL.pm b/Koha/Template/Plugin/SafeURL.pm new file mode 100644 index 0000000000..0a8847dd64 --- /dev/null +++ b/Koha/Template/Plugin/SafeURL.pm @@ -0,0 +1,66 @@ +package Koha::Template::Plugin::SafeURL; + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; +use URI; +use base 'Template::Plugin::Filter'; + +sub init { + my $self = shift; + my $name = 'safe_url'; + $self->{_DYNAMIC} = 1; + $self->install_filter($name); + return $self; +} + +sub filter { + my ( $self, $text, $args, $config ) = @_; + my $uri = URI->new($text); + if ($uri) { + return $uri; + } + + #NOTE: If it isn't a real URL, just return a safe fragment + return '#'; +} + +1; + +=head1 NAME + +Koha::Template::Plugin::SafeURL - TT Plugin for filtering whole URLs + +=head1 SYNOPSIS + +[% USE SafeURL %] + +[% $url | safe_url %] + +This filter parses the text as a URL and returns the object which +is stringified in a safe format. + +=head1 METHODS + +=head2 init + +This method installs the filter name and declares it as a dynamic filter + +=head2 filter + +Returns a stringified version of a Perl URL object + +=cut diff --git a/Koha/UI/Form/Builder/Biblio.pm b/Koha/UI/Form/Builder/Biblio.pm index 66b4002e81..c17d4965e4 100644 --- a/Koha/UI/Form/Builder/Biblio.pm +++ b/Koha/UI/Form/Builder/Biblio.pm @@ -361,10 +361,13 @@ sub build_authorized_values_list { } } + my $id_subfield = $subfield; + $id_subfield = "00" if $id_subfield eq "@"; + return { type => 'select', - id => "tag_".$tag."_subfield_".$subfield."_".$index_tag."_".$index_subfield, - name => "tag_".$tag."_subfield_".$subfield."_".$index_tag."_".$index_subfield, + id => "tag_".$tag."_subfield_".$id_subfield."_".$index_tag."_".$index_subfield, + name => "tag_".$tag."_subfield_".$id_subfield."_".$index_tag."_".$index_subfield, default => $value, values => \@authorised_values, labels => \%authorised_lib, diff --git a/Koha/Util/MARC.pm b/Koha/Util/MARC.pm index 8fb147e4b6..d3963e6e58 100644 --- a/Koha/Util/MARC.pm +++ b/Koha/Util/MARC.pm @@ -82,7 +82,7 @@ sub createMergeHash { ( !defined($tagslib) || ( defined $tagslib->{$fieldtag} && defined $tagslib->{$fieldtag}->{'tab'} - && $tagslib->{$fieldtag}->{'tab'} >= 0 ) + && ( $tagslib->{$fieldtag}->{'tab'} ? $tagslib->{$fieldtag}->{'tab'} : 0 ) >= 0 ) ) && @subfield_array ) diff --git a/Makefile.PL b/Makefile.PL index 62380aae13..62062d96b2 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -404,6 +404,7 @@ my $target_map = { 'cypress.config.ts' => 'NONE', 'tsconfig.json' => 'NONE', 'webpack.config.js' => 'NONE', + 'rspack.config.js' => 'NONE', }; =head1 CONFIGURATION OPTIONS @@ -673,9 +674,7 @@ $file_map->{'koha-tmpl/intranet-tmpl/prog/css/installer.css'} = 'blib/INTRANET_T $file_map->{'koha-tmpl/intranet-tmpl/prog/css/mainpage.css'} = 'blib/INTRANET_TMPL_DIR/prog/css/mainpage.css'; $file_map->{'koha-tmpl/intranet-tmpl/prog/css/staff-global.css'} = 'blib/INTRANET_TMPL_DIR/prog/css/staff-global.css'; $file_map->{'koha-tmpl/intranet-tmpl/prog/js/vue/dist/erm.js'} = 'blib/INTRANET_TMPL_DIR/prog/js/vue/dist/erm.js'; -$file_map->{'koha-tmpl/intranet-tmpl/prog/js/vue/dist/erm.js.LICENSE.txt'} = 'blib/INTRANET_TMPL_DIR/prog/js/vue/dist/erm.js.LICENSE.txt'; $file_map->{'koha-tmpl/intranet-tmpl/prog/js/vue/dist/preservation.js'} = 'blib/INTRANET_TMPL_DIR/prog/js/vue/dist/preservation.js'; -$file_map->{'koha-tmpl/intranet-tmpl/prog/js/vue/dist/preservation.js.LICENSE.txt'} = 'blib/INTRANET_TMPL_DIR/prog/js/vue/dist/preservation.js.LICENSE.txt'; #OPAC_TMPL_DIR $file_map->{'koha-tmpl/opac-tmpl/bootstrap/css/opac.css'} = 'blib/OPAC_TMPL_DIR/bootstrap/css/opac.css'; $file_map->{'koha-tmpl/opac-tmpl/bootstrap/css/opac-rtl.css'} = 'blib/OPAC_TMPL_DIR/bootstrap/css/opac-rtl.css'; diff --git a/acqui/addorderiso2709.pl b/acqui/addorderiso2709.pl index 4948beaab0..84e3949527 100755 --- a/acqui/addorderiso2709.pl +++ b/acqui/addorderiso2709.pl @@ -532,10 +532,9 @@ sub import_biblios_list { my $quantity = delete $iteminfos->{quantity} || 1; # Handle incorrectly named original parameters for MarcItemFieldsToOrder - $iteminfos->{location} = delete $iteminfos->{loc} if $iteminfos->{loc}; - $iteminfos->{copynumber} = delete $iteminfos->{copyno} if $iteminfos->{copyno}; + $iteminfos->{location} = delete $iteminfos->{loc} if $iteminfos->{loc}; # Price is handled as "itemprice" in the UI form to distinguish from MarcFieldsToOrder - $iteminfos->{itemprice} = delete $iteminfos->{price} if $iteminfos->{itemprice}; + $iteminfos->{itemprice} = delete $iteminfos->{price} if $iteminfos->{itemprice}; # Convert budge code to a budget id my $item_budget_code = delete $iteminfos->{budget_code}; diff --git a/acqui/orderreceive.pl b/acqui/orderreceive.pl index 550e41e810..0282020a7b 100755 --- a/acqui/orderreceive.pl +++ b/acqui/orderreceive.pl @@ -169,15 +169,16 @@ my @gst_values = map { }, split( '\|', C4::Context->preference("TaxRates") ); $template->param( - freight => $freight, - name => $bookseller->name, - active_currency => $active_currency, - currencies => $currencies->search({ rate => { '!=' => 1 } }), - invoiceincgst => $bookseller->invoiceincgst, - invoiceid => $invoice->{invoiceid}, - invoice => $invoice->{invoicenumber}, - gst_values => \@gst_values, - vendor => $bookseller, + freight => $freight, + name => $bookseller->name, + active_currency => $active_currency, + currencies => $currencies->search( { rate => { '!=' => 1 } } ), + invoiceincgst => $bookseller->invoiceincgst, + invoiceid => $invoice->{invoiceid}, + invoice => $invoice->{invoicenumber}, + gst_values => \@gst_values, + vendor => $bookseller, + UniqueItemFields => C4::Context->preference('UniqueItemFields'), ); my $patron = Koha::Patrons->find( $loggedinuser )->unblessed; diff --git a/admin/aqcontract.pl b/admin/aqcontract.pl index c1bca4a4c5..edb71f583a 100755 --- a/admin/aqcontract.pl +++ b/admin/aqcontract.pl @@ -92,7 +92,6 @@ if ( $op eq 'add_form' ) { #ADD_VALIDATE: called by add_form, used to insert/modify data in DB elsif ( $op eq 'cud-add_validate' ) { ## Please see file perltidy.ERR - $template->param( add_validate => 1 ); my $is_a_modif = $input->param("is_a_modif"); diff --git a/admin/aqplan.pl b/admin/aqplan.pl index 3b5c5d46d5..b9b4121500 100755 --- a/admin/aqplan.pl +++ b/admin/aqplan.pl @@ -119,19 +119,8 @@ my $budgets_ref = GetBudgetHierarchy( ); # build categories list -my $sth = $dbh->prepare("select distinct category from authorised_values where category like 'A%' "); -$sth->execute; - -# the list my @category_list; -# a hash, to check that some hardcoded categories exist. -my %categories; -while ( my ($category) = $sth->fetchrow_array ) { - push( @category_list, $category ); - $categories{$category} = 1; -} - # push koha system categories push( @category_list, 'MONTHS' ); push( @category_list, 'ITEMTYPES' ); diff --git a/admin/columns_settings.yml b/admin/columns_settings.yml index 5952029c5f..f459878dd3 100644 --- a/admin/columns_settings.yml +++ b/admin/columns_settings.yml @@ -411,7 +411,7 @@ modules: - columnname: holdings_datelastborrowed - - columnname: holdings_barcodes + columnname: holdings_barcode - columnname: holdings_uri - @@ -2026,6 +2026,20 @@ modules: - columnname: item_coursereserves + subscriptionst: + columns: + - + columnname: serial_serialseq + - + columnname: serial_publisheddate + - + columnname: serial_planneddate + - + columnname: serial_status + - + columnname: serial_notes + + course_list: course_reserves_table: columns: - @@ -2043,19 +2057,7 @@ modules: - columnname: notes - subscriptionst: - columns: - - - columnname: serial_serialseq - - - columnname: serial_publisheddate - - - columnname: serial_planneddate - - - columnname: serial_status - - - columnname: serial_notes - + course_items: course-items-table: columns: - diff --git a/admin/marctagstructure.pl b/admin/marctagstructure.pl index 96eeedfef2..1e89615e0d 100755 --- a/admin/marctagstructure.pl +++ b/admin/marctagstructure.pl @@ -28,6 +28,7 @@ use C4::Context; use Koha::Caches; use Koha::AuthorisedValues; use Koha::BiblioFrameworks; +use Koha::Database; # retrieve parameters my $input = CGI->new; @@ -120,6 +121,7 @@ if ($op eq 'add_form') { my $authorised_value = $input->param('authorised_value'); my $ind1_defaultvalue = $input->param('ind1_defaultvalue'); my $ind2_defaultvalue = $input->param('ind2_defaultvalue'); + my $error; if ($input->param('modif')) { $sth = $dbh->prepare( "UPDATE marc_tag_structure SET liblibrarian=? ,libopac=? ,repeatable=? ,mandatory=? ,important=? ,authorised_value=?, ind1_defaultvalue=?, ind2_defaultvalue=? WHERE frameworkcode=? AND tagfield=?" @@ -136,26 +138,40 @@ if ($op eq 'add_form') { $tagfield ); } else { - $sth = $dbh->prepare( - "INSERT INTO marc_tag_structure (tagfield,liblibrarian,libopac,repeatable,mandatory,important,authorised_value,ind1_defaultvalue,ind2_defaultvalue,frameworkcode) values (?,?,?,?,?,?,?,?,?,?)" - ); - $sth->execute($tagfield, - $liblibrarian, - $libopac, - $repeatable, - $mandatory, - $important, - $authorised_value, - $ind1_defaultvalue, - $ind2_defaultvalue, - $frameworkcode - ); + my $schema = Koha::Database->new()->schema(); + my $rs = $schema->resultset('MarcTagStructure'); + my $field = $rs->find( { tagfield => $tagfield, frameworkcode => $frameworkcode } ); + if ( !$field ) { + $sth = $dbh->prepare( + "INSERT INTO marc_tag_structure (tagfield,liblibrarian,libopac,repeatable,mandatory,important,authorised_value,ind1_defaultvalue,ind2_defaultvalue,frameworkcode) values (?,?,?,?,?,?,?,?,?,?)" + ); + $sth->execute( + $tagfield, + $liblibrarian, + $libopac, + $repeatable, + $mandatory, + $important, + $authorised_value, + $ind1_defaultvalue, + $ind2_defaultvalue, + $frameworkcode + ); + } else { + $error = 'duplicate_tagfield'; + } } - $cache->clear_from_cache("MarcStructure-0-$frameworkcode"); - $cache->clear_from_cache("MarcStructure-1-$frameworkcode"); - $cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode"); - $cache->clear_from_cache("MarcCodedFields-$frameworkcode"); - print $input->redirect("/cgi-bin/koha/admin/marctagstructure.pl?searchfield=$tagfield&frameworkcode=$frameworkcode"); + if ( !$error ) { + $cache->clear_from_cache("MarcStructure-0-$frameworkcode"); + $cache->clear_from_cache("MarcStructure-1-$frameworkcode"); + $cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode"); + $cache->clear_from_cache("MarcCodedFields-$frameworkcode"); + } + my $redirect_url = "/cgi-bin/koha/admin/marctagstructure.pl?searchfield=$tagfield&frameworkcode=$frameworkcode"; + if ($error) { + $redirect_url .= "&error=$error"; + } + print $input->redirect($redirect_url); exit; # END $OP eq ADD_VALIDATE ################## DELETE_CONFIRM ################################## @@ -200,6 +216,12 @@ if ($op eq 'add_form') { ################## DEFAULT ################################## } else { # DEFAULT + my $error_code = $input->param('error'); + if ($error_code){ + if ($error_code eq 'duplicate_tagfield'){ + $template->param('blocking_error' => $error_code); + } + } # here, $op can be unset or set to "cud-framework_create_confirm". if ($searchfield ne '') { $template->param(searchfield => $searchfield); diff --git a/admin/searchengine/elasticsearch/mappings.yaml b/admin/searchengine/elasticsearch/mappings.yaml index 929f2f9410..8ec0c114c1 100644 --- a/admin/searchengine/elasticsearch/mappings.yaml +++ b/admin/searchengine/elasticsearch/mappings.yaml @@ -3125,21 +3125,6 @@ biblios: marc_type: marc21 sort: 1 suggestible: '' - - facet: '' - marc_field: 752ad - marc_type: marc21 - sort: 1 - suggestible: '' - - facet: '' - marc_field: 210a - marc_type: unimarc - sort: 1 - suggestible: '' - - facet: '' - marc_field: 214a - marc_type: unimarc - sort: 1 - suggestible: '' opac: 1 staff_client: 1 type: '' @@ -3194,6 +3179,21 @@ biblios: marc_type: marc21 sort: 1 suggestible: '' + - facet: '' + marc_field: 752ad + marc_type: marc21 + sort: 1 + suggestible: '' + - facet: '' + marc_field: 210a + marc_type: unimarc + sort: 1 + suggestible: '' + - facet: '' + marc_field: 214a + marc_type: unimarc + sort: 1 + suggestible: '' opac: 1 staff_client: 1 type: '' @@ -3768,7 +3768,7 @@ biblios: sort: 1 suggestible: 1 - facet: '' - marc_field: '246' + marc_field: 246abnp marc_type: marc21 sort: 0 suggestible: 1 @@ -4143,7 +4143,7 @@ biblios: sort: 1 suggestible: '' - facet: '' - marc_field: '246' + marc_field: 246abnp marc_type: marc21 sort: 1 suggestible: '' @@ -4184,7 +4184,7 @@ biblios: sort: 1 suggestible: '' - facet: '' - marc_field: '246' + marc_field: 246abnp marc_type: marc21 sort: 1 suggestible: '' @@ -4196,7 +4196,7 @@ biblios: mandatory: ~ mappings: - facet: '' - marc_field: '246' + marc_field: 246abnp marc_type: marc21 sort: 1 suggestible: '' diff --git a/api/v1/swagger/definitions/erm_usage_data_provider.yaml b/api/v1/swagger/definitions/erm_usage_data_provider.yaml index baa6c5d092..ed6bdfe570 100644 --- a/api/v1/swagger/definitions/erm_usage_data_provider.yaml +++ b/api/v1/swagger/definitions/erm_usage_data_provider.yaml @@ -73,6 +73,11 @@ properties: type: - string - "null" + service_platform: + description: service platform of the harvester + type: + - string + - "null" metric_type: description: metric type of the harvester when reporting type: diff --git a/api/v1/swagger/definitions/hold.yaml b/api/v1/swagger/definitions/hold.yaml index 85bcd66900..2ba3367e04 100644 --- a/api/v1/swagger/definitions/hold.yaml +++ b/api/v1/swagger/definitions/hold.yaml @@ -16,6 +16,11 @@ properties: biblio_id: type: integer description: Internal biblio identifier + deleted_biblio_id: + type: + - integer + - "null" + description: Internal deleted biblio identifier item_group_id: type: - string diff --git a/api/v1/swagger/definitions/vendor.yaml b/api/v1/swagger/definitions/vendor.yaml index 3bf8a17977..262db4fb10 100644 --- a/api/v1/swagger/definitions/vendor.yaml +++ b/api/v1/swagger/definitions/vendor.yaml @@ -119,6 +119,11 @@ properties: description: List of aliases items: $ref: "vendor_alias.yaml" + subscriptions_count: + type: + - integer + - "null" + description: Number of linked subscriptions additionalProperties: false required: - name diff --git a/api/v1/swagger/paths/acquisitions_baskets.yaml b/api/v1/swagger/paths/acquisitions_baskets.yaml index 38e70a836e..f3e8a0d2cb 100644 --- a/api/v1/swagger/paths/acquisitions_baskets.yaml +++ b/api/v1/swagger/paths/acquisitions_baskets.yaml @@ -23,6 +23,7 @@ type: string enum: - extended_attributes + - library collectionFormat: csv produces: - application/json diff --git a/api/v1/swagger/paths/acquisitions_funds.yaml b/api/v1/swagger/paths/acquisitions_funds.yaml index c262e98e2e..9c45ebd94a 100644 --- a/api/v1/swagger/paths/acquisitions_funds.yaml +++ b/api/v1/swagger/paths/acquisitions_funds.yaml @@ -90,6 +90,7 @@ type: string enum: - extended_attributes + - library collectionFormat: csv produces: - application/json @@ -149,6 +150,7 @@ type: string enum: - extended_attributes + - library collectionFormat: csv produces: - application/json diff --git a/api/v1/swagger/paths/acquisitions_vendors.yaml b/api/v1/swagger/paths/acquisitions_vendors.yaml index ed817cc2a1..991419e541 100644 --- a/api/v1/swagger/paths/acquisitions_vendors.yaml +++ b/api/v1/swagger/paths/acquisitions_vendors.yaml @@ -35,6 +35,7 @@ type: string enum: - aliases + - subscriptions+count collectionFormat: csv responses: "200": diff --git a/api/v1/swagger/paths/biblios.yaml b/api/v1/swagger/paths/biblios.yaml index 005d75ec23..75e9dad401 100644 --- a/api/v1/swagger/paths/biblios.yaml +++ b/api/v1/swagger/paths/biblios.yaml @@ -472,6 +472,7 @@ - item_type - in_bundle - bundle_host + - bundle_host.biblio - bundle_items_lost+count - bundle_items_not_lost+count - course_item.course_reserves.course diff --git a/api/v1/swagger/paths/erm_users.yaml b/api/v1/swagger/paths/erm_users.yaml index 146f6b2591..654bbefa8b 100644 --- a/api/v1/swagger/paths/erm_users.yaml +++ b/api/v1/swagger/paths/erm_users.yaml @@ -23,6 +23,7 @@ type: string enum: - extended_attributes + - library collectionFormat: csv produces: - application/json diff --git a/api/v1/swagger/paths/holds.yaml b/api/v1/swagger/paths/holds.yaml index b75ad24e50..7d75826d93 100644 --- a/api/v1/swagger/paths/holds.yaml +++ b/api/v1/swagger/paths/holds.yaml @@ -104,7 +104,7 @@ - cancellation_requested - biblio - pickup_library - collectionFormat: csv + collectionFormat: csv produces: - application/json responses: diff --git a/api/v1/swagger/paths/suggestions.yaml b/api/v1/swagger/paths/suggestions.yaml index a17d5d1ac8..4ce5511b31 100644 --- a/api/v1/swagger/paths/suggestions.yaml +++ b/api/v1/swagger/paths/suggestions.yaml @@ -269,6 +269,7 @@ type: string enum: - extended_attributes + - library collectionFormat: csv produces: - application/json diff --git a/authorities/authorities.pl b/authorities/authorities.pl index 761c1f529d..2133008f4f 100755 --- a/authorities/authorities.pl +++ b/authorities/authorities.pl @@ -540,7 +540,6 @@ my $error = $input->param('error'); my $authid = $input->param('authid') =~ s/\D//gr ; # if authid exists, it's a modif, not a new authority. We remove from authid all non-digit characters just in case the CGI parameter contains weird characters like spaces my $op = $input->param('op'); -my $nonav = $input->param('nonav'); my $myindex = $input->param('index'); my $linkid=$input->param('linkid'); my $authtypecode = $input->param('authtypecode'); @@ -570,7 +569,7 @@ my ($template, $loggedinuser, $cookie) type => "intranet", flagsrequired => {editauthorities => 1}, }); -$template->param(nonav => $nonav,index=>$myindex,authtypecode=>$authtypecode,breedingid=>$breedingid, count=>$count); +$template->param( index => $myindex, authtypecode => $authtypecode, breedingid => $breedingid, count => $count ); $tagslib = GetTagsLabels(1,$authtypecode); $mandatory_z3950 = GetMandatoryFieldZ3950($authtypecode); @@ -632,15 +631,6 @@ if ($op eq "cud-add") { duplicateauthvalue => $duplicateauthvalue->{'authorized'}->[0]->{'heading'}, ); } -} elsif ($op eq "cud-delete") { -#------------------------------------------------------------------------------------------------------------------------------ - DelAuthority({ authid => $authid }); - if ($nonav){ - print $input->redirect("auth_finder.pl"); - }else{ - print $input->redirect("authorities-home.pl?authid=0"); - } - exit; } else { if ( $op eq "duplicate" ) { $authid = ""; diff --git a/authorities/export.pl b/authorities/export.pl index 70a5157140..0703da840b 100755 --- a/authorities/export.pl +++ b/authorities/export.pl @@ -20,7 +20,7 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user( my $op = $query->param("op"); my $format = $query->param("format"); my $error = ''; -if ( $op eq "cud-export" ) { +if ( $op eq "export" ) { my $authid = $query->param("authid"); if ($authid) { diff --git a/catalogue/search.pl b/catalogue/search.pl index 7c6545376b..ba97a75f1c 100755 --- a/catalogue/search.pl +++ b/catalogue/search.pl @@ -148,7 +148,6 @@ use C4::Languages qw( getlanguage getLanguages ); use C4::Koha qw( getitemtypeimagelocation GetAuthorisedValues ); use URI::Escape; use POSIX qw(ceil floor); -use C4::Search qw( searchResults enabled_staff_search_views z3950_search_args new_record_from_zebra ); use Koha::ItemTypes; use Koha::Library::Groups; @@ -243,7 +242,7 @@ my @search_groups = my $branch_limit = ''; my $limit_param = $cgi->param('limit'); -if ( $limit_param and $limit_param =~ /branch:([\w-]+)/ ) { +if ( $limit_param and $limit_param =~ /^branch:([\w-]+)/ ) { $branch_limit = $1; } @@ -425,9 +424,9 @@ if ($params->{'limit-yr'}) { # $ %z3950p will be a hash ref if the indexes are present (advacned search), otherwise undef my $z3950par; my $indexes2z3950 = { - kw=>'title', au=>'author', 'au,phr'=>'author', nb=>'isbn', ns=>'issn', - 'lcn,phr'=>'dewey', su=>'subject', 'su,phr'=>'subject', - ti=>'title', 'ti,phr'=>'title', se=>'title' + kw => 'title', au => 'author', 'au,phr' => 'author', nb => 'isbn', ns => 'issn', + callnum => 'dewey', su => 'subject', 'su,phr' => 'subject', + ti => 'title', 'ti,phr' => 'title', se => 'title' }; for (my $ii = 0; $ii < @operands; ++$ii) { diff --git a/cataloguing/value_builder/stocknumberAV.pl b/cataloguing/value_builder/stocknumberAV.pl index c158ec7688..dedef7968a 100755 --- a/cataloguing/value_builder/stocknumberAV.pl +++ b/cataloguing/value_builder/stocknumberAV.pl @@ -50,12 +50,14 @@ my $builder = sub { function Click$params->{id}(ev) { ev.preventDefault(); var code = document.getElementById(ev.data.id); + const csrf_token = document.querySelector('meta[name="csrf-token"]').getAttribute('content'); \$.ajax({ url: '/cgi-bin/koha/cataloguing/plugin_launcher.pl', type: 'POST', data: { 'plugin_name': 'stocknumberAV.pl', 'code' : code.value, + 'csrf_token': csrf_token }, success: function(data){ var field = document.getElementById(ev.data.id); diff --git a/circ/add_message.pl b/circ/add_message.pl index 08cf1e4d9f..aa59914556 100755 --- a/circ/add_message.pl +++ b/circ/add_message.pl @@ -97,7 +97,7 @@ if ( $op eq 'cud-edit_message' && $message_id ) { my $url = $input->referer; if ($url) { - if ( $url =~ m|circulation\.pl$| ) { + if ( $url =~ m/(circulation\.pl|members\/files\.pl)$/ ) { # Trick for POST form from batch checkouts $url .= "?borrowernumber=$borrowernumber"; diff --git a/circ/article-request-slip.pl b/circ/article-request-slip.pl index 5ab59576c9..ed8bf8aa4e 100755 --- a/circ/article-request-slip.pl +++ b/circ/article-request-slip.pl @@ -81,6 +81,7 @@ $template->param( caller => 'article-request', plain => 0, style => $style, + id => 'ar_slip', ); output_html_with_http_headers $cgi, $cookie, $template->output; diff --git a/circ/circulation.pl b/circ/circulation.pl index d1c2b3b0cf..a354c1257d 100755 --- a/circ/circulation.pl +++ b/circ/circulation.pl @@ -112,7 +112,7 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user ( } ); -my $op = $query->param('op'); +my $op = $query->param('op') // ''; my $override_high_holds = $query->param('override_high_holds'); my $override_high_holds_tmp = $query->param('override_high_holds_tmp'); @@ -364,19 +364,16 @@ if (@$barcodes && $op eq 'cud-checkout') { } if ( $issuingimpossible->{'STATS'} ) { - $template->param( STATS => 1 ); + my ( $stats_return, $stats_messages, $stats_iteminformation, $stats_borrower ) = + AddReturn( $item->barcode, C4::Context->userenv->{'branch'}, undef, undef, 1 ); - if ( $item->onloan ) { - my ( $stats_return, $stats_messages, $stats_iteminformation, $stats_borrower ) = - AddReturn( $item->barcode, C4::Context->userenv->{'branch'}, undef, undef, 1 ); - - $template->param( - CHECKEDIN => $stats_return, - MESSAGES => $stats_messages, - ITEM => $stats_iteminformation, - BORROWER => $stats_borrower, - ); - } + $template->param( + STATS => 1, + CHECKEDIN => $stats_return, + MESSAGES => $stats_messages, + ITEM => $stats_iteminformation, + BORROWER => $stats_borrower, + ); #increment items.localuse my $localuse_count = $item->localuse; diff --git a/circ/hold-transfer-slip.pl b/circ/hold-transfer-slip.pl index 435d1c14e0..dab16202d0 100755 --- a/circ/hold-transfer-slip.pl +++ b/circ/hold-transfer-slip.pl @@ -54,6 +54,7 @@ $template->param( slip => $slip ) if ($slip); $template->param( caller => 'hold-transfer' ); $template->param( plain => !$is_html ); $template->param( style => $style ); +$template->param( id => 'reserve_slip' ); output_html_with_http_headers $input, $cookie, $template->output; diff --git a/circ/pendingreserves.pl b/circ/pendingreserves.pl index 366d0009af..b85cf5c90e 100755 --- a/circ/pendingreserves.pl +++ b/circ/pendingreserves.pl @@ -194,7 +194,7 @@ if ( $holds->count ) { # patrons count per biblio my $patrons_count = { map { $_->{biblionumber} => $_->{patrons_count} } @{ Koha::Holds->search( - { 'suspend' => 0 }, + { 'suspend' => 0, 'found' => undef }, { select => [ 'biblionumber', { count => { distinct => 'borrowernumber' } } ], as => [qw( biblionumber patrons_count )], diff --git a/circ/returns.pl b/circ/returns.pl index 72e004a795..cb39bd4dfa 100755 --- a/circ/returns.pl +++ b/circ/returns.pl @@ -143,7 +143,7 @@ foreach ( $query->param ) { push( @inputloop, \%input ); } -my $op = $query->param('op'); +my $op = $query->param('op') // ''; ############ # Deal with the requests.... diff --git a/circ/transfer-slip.pl b/circ/transfer-slip.pl index 5282bbe44e..b8f8a5031f 100755 --- a/circ/transfer-slip.pl +++ b/circ/transfer-slip.pl @@ -60,6 +60,7 @@ $template->param( caller => 'cud-transfer', stylesheet => C4::Context->preference("SlipCSS"), style => $style, + id => 'transfer_slip', ); output_html_with_http_headers $input, $cookie, $template->output; diff --git a/circ/waitingreserves.pl b/circ/waitingreserves.pl index 0ffebe1b24..9322a0f779 100755 --- a/circ/waitingreserves.pl +++ b/circ/waitingreserves.pl @@ -145,23 +145,24 @@ if ($item && $tab eq 'holdsover' && !@cancel_result) { exit; sub cancel { - my ($item, $borrowernumber, $fbr, $tbr, $skip_transfers ) = @_; + my ( $itemnumber, $borrowernumber, $fbr, $tbr, $skip_transfers ) = @_; my $transfer = $fbr ne $tbr; # XXX && !$nextreservinfo; + my $item = Koha::Items->find( $itemnumber ); return if $transfer && $skip_transfers; - my ( $messages, $nextreservinfo ) = ModReserveCancelAll( $item, $borrowernumber ); + my ( $messages, $nextreservinfo ) = ModReserveCancelAll( $itemnumber, $borrowernumber ); # if the document is not in his homebranch location and there is not reservation after, we transfer it - if ($transfer && !$nextreservinfo) { - ModItemTransfer( $item, $fbr, $tbr, 'CancelReserve' ); + if ( $transfer && !$nextreservinfo && !$item->itemlost ) { + ModItemTransfer( $itemnumber, $fbr, $tbr, 'CancelReserve' ); } # if we have a result if ($nextreservinfo) { my %res; my $patron = Koha::Patrons->find( $nextreservinfo ); - my $title = Koha::Items->find( $item )->biblio->title; + my $title = $item->biblio->title; if ( $messages->{'transfert'} ) { $res{messagetransfert} = $messages->{'transfert'}; $res{branchcode} = $messages->{'transfert'}; @@ -171,7 +172,7 @@ sub cancel { $res{nextreservnumber} = $nextreservinfo; $res{nextreservsurname} = $patron->surname; $res{nextreservfirstname} = $patron->firstname; - $res{nextreservitem} = $item; + $res{nextreservitem} = $itemnumber; $res{nextreservtitle} = $title; $res{waiting} = $messages->{'waiting'} ? 1 : 0; diff --git a/debian/docs/koha-worker.xml b/debian/docs/koha-worker.xml index f230b68fcf..56a5f0cb82 100644 --- a/debian/docs/koha-worker.xml +++ b/debian/docs/koha-worker.xml @@ -63,7 +63,8 @@ Allows specifying the queue worker (defaults to 'default'). - Current queues are: default, long_tasks, elastic_index. + Current queues are: default, long_tasks. + Note: There used to be a queue called elastic_index, but since the introduction of koha-es-indexer this queue should not be active. diff --git a/debian/scripts/koha-dump b/debian/scripts/koha-dump index f58c4b2022..e8e1b06df3 100755 --- a/debian/scripts/koha-dump +++ b/debian/scripts/koha-dump @@ -47,7 +47,7 @@ $scriptname [--quiet|-q] [--exclude-indexes] instancename1 [instancename2...] $scriptname -h|--help --schema-only Dump only the database schema - --exclude-indexes Include Zebra indexes on the backup + --exclude-indexes Exclude Zebra indexes from the backup --exclude-logs Exclude /var/log/koha/name from the backup --uploaded_files Include uploaded files. --uploaded_temp_files Include temporary uploaded files. @@ -124,30 +124,37 @@ dump_instance() output="$output to $metadump" [ "$quiet" = "no" ] && echo "$output" + # tar has exit status 1 if any file has changed while being read, + # which is likely to happen as the logfiles are included. + set +e + if [ "$exclude_logs" = "yes" ]; then - tar -czf "$metadump" -C / $excludes \ - "etc/koha/sites/$name" \ - "etc/apache2/sites-available/$instancefile" \ - "etc/apache2/sites-enabled/$instancefile" \ - "var/lib/koha/$name" \ - $uploaded_files_dir \ - $uploaded_temp_files_dir - - chown "root:$name-koha" "$metadump" - chmod g+r "$metadump" + tar -czf "$metadump" -C / $excludes \ + "etc/koha/sites/$name" \ + "etc/apache2/sites-available/$instancefile" \ + "etc/apache2/sites-enabled/$instancefile" \ + "var/lib/koha/$name" \ + $uploaded_files_dir \ + $uploaded_temp_files_dir else - tar -czf "$metadump" -C / $excludes \ - "etc/koha/sites/$name" \ - "etc/apache2/sites-available/$instancefile" \ - "etc/apache2/sites-enabled/$instancefile" \ - "var/lib/koha/$name" \ - "var/log/koha/$name" \ - $uploaded_files_dir \ - $uploaded_temp_files_dir + tar -czf "$metadump" -C / $excludes \ + "etc/koha/sites/$name" \ + "etc/apache2/sites-available/$instancefile" \ + "etc/apache2/sites-enabled/$instancefile" \ + "var/lib/koha/$name" \ + "var/log/koha/$name" \ + $uploaded_files_dir \ + $uploaded_temp_files_dir + fi + + if [ "$?" != "1" -a "$?" != "0" ]; then + exit $? + fi + + set -e chown "root:$name-koha" "$metadump" chmod g+r "$metadump" - fi [ "$quiet" = "no" ] && echo "Done." fi diff --git a/debian/scripts/koha-elasticsearch b/debian/scripts/koha-elasticsearch index a5428175ac..f337b8fa71 100755 --- a/debian/scripts/koha-elasticsearch +++ b/debian/scripts/koha-elasticsearch @@ -90,12 +90,12 @@ run_rebuild_elasticsearch() KOHA_BINDIR=${KOHA_HOME}/misc fi - if [ "${clo_commit_size}" > 0 ]; then + if [ "${clo_commit_size}" -gt 0 ] 2>/dev/null; then commit_size=${clo_commit_size} fi rebuild_opts="--commit ${commit_size}" - if [ "${clo_processes}" > 0 ]; then + if [ "${clo_processes}" -gt 0 ] 2>/dev/null; then processes=${clo_processes} fi rebuild_opts="${rebuild_opts} --processes ${processes}" diff --git a/debian/scripts/koha-list b/debian/scripts/koha-list index 3f3fcc90f2..8cfa034700 100755 --- a/debian/scripts/koha-list +++ b/debian/scripts/koha-list @@ -280,21 +280,21 @@ email turned on. Usage: $scriptname [--enabled|--disabled] [--email|--noemail] [--sip|--nosip] [-h] Options: - --enabled Show enabled instances - --disabled Show disabled instances - --elasticsearch Show instances with Elasticsearch enabled - --noelasticsarch Show instances with Elasticsearch disabled - --email Show instances with email enabled - --noemail Show instances with email disabled - --sip Show instances with SIP enabled - --nosip Show instances with SIP disabled - --plack Show instances with Plack enabled - --noplack Show instances with Plack disabled - --letsencrypt Show instances with letsencrypt enabled - --noletsencrypt Show instances with letsencrypt disabled - --z3950 Show instances with Z39.50/SRU enabled - --noz3950 Show instances with Z39.50/SRU disabled - --help | -h Show this help + --enabled Show enabled instances + --disabled Show disabled instances + --elasticsearch Show instances with Elasticsearch enabled + --noelasticsearch Show instances with Elasticsearch disabled + --email Show instances with email enabled + --noemail Show instances with email disabled + --sip Show instances with SIP enabled + --nosip Show instances with SIP disabled + --plack Show instances with Plack enabled + --noplack Show instances with Plack disabled + --letsencrypt Show instances with letsencrypt enabled + --noletsencrypt Show instances with letsencrypt disabled + --z3950 Show instances with Z39.50/SRU enabled + --noz3950 Show instances with Z39.50/SRU disabled + --help | -h Show this help The filtering options can be combined, and you probably want to do this (except --email and --noemail, or --enabled and --disabled, that's just silly.) diff --git a/debian/scripts/koha-run-backups b/debian/scripts/koha-run-backups index 4ad2d38c94..91401ce6aa 100755 --- a/debian/scripts/koha-run-backups +++ b/debian/scripts/koha-run-backups @@ -70,7 +70,7 @@ if ! test $days -gt 0 ; then exit 1 fi -for name in $(koha-list --enabled | grep -Fxv demo) +for name in $(koha-list --enabled) do if koha-dump ${exclude_indexes} ${exclude_logs} "$name" > /dev/null; then # Only delete old backups if dump script return success. diff --git a/debian/scripts/koha-translate b/debian/scripts/koha-translate index b9a8ec835d..c06bffc824 100755 --- a/debian/scripts/koha-translate +++ b/debian/scripts/koha-translate @@ -86,7 +86,7 @@ print_installed() ( ls -1 $KOHA_HOME/$OPAC_TMPL/bootstrap/ ; \ ls -1 $KOHA_HOME/$OPAC_TMPL/prog/ 2> /dev/null ) | \ sort | uniq | \ - grep -v -e images -e itemtypeimg -x -e en -e css -e js -e less -e lib + grep -v -e images -e itemtypeimg -x -e en -e css -e js -e less -e lib -e sound } install_lang() diff --git a/debian/scripts/koha-worker b/debian/scripts/koha-worker index d1d1601357..aa51c90c13 100755 --- a/debian/scripts/koha-worker +++ b/debian/scripts/koha-worker @@ -48,12 +48,15 @@ $scriptname -h|--help --stop Stop the worker daemon for the specified instances --restart Restart the worker daemon for the specified instances --queue Specify the queue/worker to restart - 'default' is used if not specified - current queues are: default, long_tasks, elastic_index + current queues are: default, long_tasks --status Show the status of the worker for the specified instances --quiet|-q Make the script quiet about non existent instance names (useful for calling from another scripts). --help|-h Display this help message +Note: There used to be a queue called elastic_index, but since the introduction +of koha-es-indexer this queue should not be active. + EOF } diff --git a/debian/templates/SIPconfig.xml b/debian/templates/SIPconfig.xml index e79a2950b6..f0a408c67b 100644 --- a/debian/templates/SIPconfig.xml +++ b/debian/templates/SIPconfig.xml @@ -10,6 +10,9 @@ diff --git a/debian/templates/apache-shared-intranet-plack.conf b/debian/templates/apache-shared-intranet-plack.conf index 7f9f47e1e1..bcee399443 100644 --- a/debian/templates/apache-shared-intranet-plack.conf +++ b/debian/templates/apache-shared-intranet-plack.conf @@ -22,6 +22,9 @@ # Point the intranet site to Plack ProxyPass /index.html "unix:/var/run/koha/${instance}/plack.sock|http://localhost/intranet/mainpage.pl" ProxyPassReverse /index.html "unix:/var/run/koha/${instance}/plack.sock|http://localhost/intranet/mainpage.pl" + ProxyPass /cgi-bin/koha/svc "unix:/var/run/koha/${instance}/plack.sock|http://localhost/intranet_svc" + ProxyPassReverse /cgi-bin/koha/svc "unix:/var/run/koha/${instance}/plack.sock|http://localhost/intranet_svc" + ProxyPass /cgi-bin/koha "unix:/var/run/koha/${instance}/plack.sock|http://localhost/intranet" ProxyPassReverse /cgi-bin/koha "unix:/var/run/koha/${instance}/plack.sock|http://localhost/intranet" diff --git a/debian/templates/plack.psgi b/debian/templates/plack.psgi index bf31ecf152..7dd49f3ae5 100644 --- a/debian/templates/plack.psgi +++ b/debian/templates/plack.psgi @@ -56,6 +56,10 @@ my $intranet = Plack::App::CGIBin->new( root => $ENV{DEV_INSTALL}? $home: "$home/intranet/cgi-bin" )->to_app; +my $intranet_svc = Plack::App::CGIBin->new( + root => $ENV{DEV_INSTALL}? "$home/svc": "$home/intranet/cgi-bin/svc" +)->to_app; + my $opac = Plack::App::CGIBin->new( root => $ENV{DEV_INSTALL}? "$home/opac": "$home/opac/cgi-bin/opac" )->to_app; @@ -117,6 +121,14 @@ builder { enable "+Koha::Middleware::CSRF"; $intranet; }; + mount '/intranet_svc' => builder { + if ( Log::Log4perl->get_logger('plack-intranet')->has_appenders ){ + enable 'Log4perl', category => 'plack-intranet'; + enable 'LogWarn'; + } + enable "+Koha::Middleware::CSRF"; + $intranet_svc; + }; mount '/api/v1/app.pl' => builder { if ( Log::Log4perl->get_logger('plack-api')->has_appenders ){ enable 'Log4perl', category => 'plack-api'; diff --git a/docs/teams.yaml b/docs/teams.yaml index e33250984e..5233e291ad 100644 --- a/docs/teams.yaml +++ b/docs/teams.yaml @@ -1405,6 +1405,8 @@ team: - name: Pedro Amorim - name: Matt Blenkinsop - name: Thomas Klausner + - name: Paul Derscheid + - name: Chris Cormack te: - area: UI Design name: Owen Leonard @@ -1432,6 +1434,8 @@ team: - name: Kelly McElligott - name: Rasa Šatinskienė - name: Heather Hernandez + translation: + name: Jonathan Druart meeting_facilitator: - name: Paul Derscheid packaging: @@ -1447,3 +1451,83 @@ team: - name: Liz Rea newsletter: name: Michael Kuhn + 25.05: + release_date: 1747868400 + manager: + name: Katrin Fischer + manager_assistants: + - name: Tomás Cohen Arazi + - name: Martin Renvoize + - name: Jonathan Druart + maintainer: + - version: 24.11 + name: Paul Derscheid + - version: 24.05 + name: Wainui Witika-Park + - version: 23.11 + name: Fridolin Somers + - version: 22.11 + - name: Laura Escamilla + qa_manager: + name: Martin Renvoize + qa: + - name: Victor Grousset + - name: Lisette Scheer + - name: Emily Lamancusa + - name: David Cook + - name: Jonathan Druart + - name: Julian Maurice + - name: Baptiste Wojtowski + - name: Paul Derscheid + - name: Aleisha Amohia + - name: Laura Escamilla + - name: Tomás Cohen Arazi + - name: Kyle M Hall + - name: Nick Clemens + - name: Lucas Gass + - name: Marcel de Rooy + - name: Matt Blenkinsop + - name: Pedro Amorim + - name: Brendan Lawlor + - name: Thomas Klausner + security_manager: + - name: Tomás Cohen Arazi + te: + - area: UI Design + name: Owen Leonard + - area: REST API + name: Tomás Cohen Arazi + - area: Zebra + name: Fridolin Somers + bugwrangler: + - name: Michaela Sieber + - name: Jacob O'Mara + - name: Jake Deery + documentation: + name: Philip Orr + documentation_team: + - name: Aude Charillon + - name: David Nind + - name: Caroline Cyr La Rose + translation: + name: Jonathan Druart + meeting_facilitator: + - name: Paul Derscheid + packaging: + - name: Mason James + ktd: + - name: Tomás Cohen Arazi + ci: + - name: Jonathan Druart + - name: Tomás Cohen Arazi + - name: Jake Deery + wiki: + - name: George Williams + - name: Thomas Dukleth + - name: Jonathan Druart + - name: Martin Renvoize + website: + - name: David Nind + - name: Lauren Purton + newsletter: + name: Michael Kuhn diff --git a/errors/400.pl b/errors/400.pl index 0bddd49fc8..8ae328dcce 100755 --- a/errors/400.pl +++ b/errors/400.pl @@ -41,4 +41,7 @@ my $status = '400 Bad Request'; if ( C4::Context->is_internal_PSGI_request() ) { $status = '200 OK'; } + +#NOTE: We're not setting/updating the cookie here +$cookie = ''; output_with_http_headers $query, $cookie, $template->output, 'html', $status; diff --git a/errors/401.pl b/errors/401.pl index f5761fcb35..4b8f748cf5 100755 --- a/errors/401.pl +++ b/errors/401.pl @@ -40,4 +40,6 @@ my $status = '401 Unauthorized'; if ( C4::Context->is_internal_PSGI_request() ) { $status = '200 OK'; } +#NOTE: We're not setting/updating the cookie here +$cookie = ''; output_with_http_headers $query, $cookie, $template->output, 'html', $status; diff --git a/errors/402.pl b/errors/402.pl index 835aed3ea3..b9d3444368 100755 --- a/errors/402.pl +++ b/errors/402.pl @@ -41,4 +41,6 @@ my $status = '402 Payment Required'; if ( C4::Context->is_internal_PSGI_request() ) { $status = '200 OK'; } +#NOTE: We're not setting/updating the cookie here +$cookie = ''; output_with_http_headers $query, $cookie, $template->output, 'html', $status; diff --git a/errors/403.pl b/errors/403.pl index b83c014de8..c75c2a5293 100755 --- a/errors/403.pl +++ b/errors/403.pl @@ -43,4 +43,6 @@ my $status = '403 Forbidden'; if ( C4::Context->is_internal_PSGI_request() ) { $status = '200 OK'; } +#NOTE: We're not setting/updating the cookie here +$cookie = ''; output_with_http_headers $query, $cookie, $template->output, 'html', $status; diff --git a/errors/404.pl b/errors/404.pl index 049db4aa40..a375d8d8cb 100755 --- a/errors/404.pl +++ b/errors/404.pl @@ -41,4 +41,7 @@ my $status = '404 Not Found'; if ( C4::Context->is_internal_PSGI_request() ) { $status = '200 OK'; } + +#NOTE: We're not setting/updating the cookie here +$cookie = ''; output_with_http_headers $query, $cookie, $template->output, 'html', $status; diff --git a/errors/500.pl b/errors/500.pl index 26dab6f93b..5f216dd61b 100755 --- a/errors/500.pl +++ b/errors/500.pl @@ -41,4 +41,6 @@ my $status = '500 Internal Server Error'; if ( C4::Context->is_internal_PSGI_request() ) { $status = '200 OK'; } +#NOTE: We're not setting/updating the cookie here +$cookie = ''; output_with_http_headers $query, $cookie, $template->output, 'html', $status; diff --git a/etc/SIPconfig.xml b/etc/SIPconfig.xml index 1816b91a23..1988477691 100644 --- a/etc/SIPconfig.xml +++ b/etc/SIPconfig.xml @@ -19,6 +19,9 @@ user='koha' group='koha' pid_file='/var/run/sipserver.pid' + custom_tcp_keepalive='0' + custom_tcp_keepalive_time='7200' + custom_tcp_keepalive_intvl='75' /> @@ -56,6 +59,7 @@ + diff --git a/etc/zebradb/marc_defs/normarc/biblios/biblio-koha-indexdefs.xml b/etc/zebradb/marc_defs/normarc/biblios/biblio-koha-indexdefs.xml deleted file mode 100644 index 161ce6a9f9..0000000000 --- a/etc/zebradb/marc_defs/normarc/biblios/biblio-koha-indexdefs.xml +++ /dev/null @@ -1,1019 +0,0 @@ - - - marc:datafield[@tag='999']/marc:subfield[@code='c'] - - - llength:w - - - rtype:w - - - Bib-level:w - - - - Control-number:w - - - - Microform-generation:n - - - Material-type:w - - - ff7-00:w - - - ff7-01:w - - - ff7-02:w - - - ff7-01-02:w - - - - date-entered-on-file:n - - - date-entered-on-file:s - - - pubdate:w - - - pubdate:n - - - pubdate:y - - - pubdate:s - - - pl:w - - - ta:w - - - ff8-23:w - - - ff8-29:w - - - lf:w - - - bio:w - - - ln:w - - - ctype:w - - - Record-source:w - - - - LC-card-number:w - Identifier-standard:w - - - - BNB-card-number:w - BGF-number:w - Number-db:w - Number-natl-biblio:w - Identifier-standard:w - - - - ISBN:w - Identifier-standard:w - - - - ISBN:w - Identifier-standard:w - - - - ISSN:w - ISBN:w - - - - ISSN:w - Identifier-standard:w - - - - Identifier-standard:w - - - - Identifier-standard:w - - - - Report-number:w - Identifier-standard:w - - - - Identifier-publisher-for-music:w - Identifier-standard:w - - - - CODEN:w - Identifier-standard:w - - - - Code-institution:w - Record-source:w - - - - ln:w - - - - Code-geographic:w - - - - NLM-call-number:w - - - - UDC-classification:w - - - - Dewey-classification:w - Dewey-classification:s - - - - Cross-Reference:w - Koha-Auth-Number:w - - - - Author:w - Author:p - Author:s - Editor:w - Author-personal-bibliography:w - Author-personal-bibliography:p - Author-personal-bibliography:s - - - - Author:w - Author-title:w - Author-name-personal:w - Name:w - Name-and-title:w - Personal-name:w - - - - Koha-Auth-Number:w - - - - Author:w - Author-title:w - Author-name-corporate:w - Name:w - Name-and-title:w - Corporate-name:w - - - - Koha-Auth-Number:w - - - - Author:w - Author-title:w - Author-name-corporate:w - Name:w - Name-and-title:w - Conference-name:w - - - - Thematic-number:w - - - - Thematic-number:w - - - - Music-key:w - - - - Koha-Auth-Number:w - - - - Title:w - Title-uniform:w - - - - Title:w - Title-abbreviated:w - - - - Title:w - Title-key:w - - - - Thematic-number:w - - - - Music-key:w - - - - Thematic-number:w - - - - Title:w - Title:p - Title-uniform:w - - - - Title-cover:w - Title-cover:p - Title-cover:s - Title:w - Title:p - Title:s - - - - Author:w - Author-in-order:w - Author-in-order:p - Author-in-order:s - - - - Cross-Reference:w - Koha-Auth-Number:w - - - - Title:w - Title:p - - - - Title:w - Title:p - Title-abbreviated:w - Title-expanded:w - Title-former:w - - - - pl:w - pl:p - - - - Publisher:w - Publisher:p - - - - copydate:w - copydate:s - - - - pl:w - - - - Extent:w - Extent:p - - - - Title-series:w - Title-series:p - - - - Koha-Auth-Number:w - - - - Title-series:w - Title-series:p - Title:w - Title-series:w - - - - Title-series:w - Title-series:p - - - - Title:w - Title-series:w - - - - Koha-Auth-Number:w - - - - Material-type:w - - - - Note:w - Note:p - - - - Indexed-by:w - - - - Abstract:w - Abstract:p - - - - Name-and-title:w - Name:w - Personal-name:w - Subject-name-personal:w - Subject:w - Subject:p - - - - Name-and-title:w - Title:w - Subject:w - Subject:p - - - - Koha-Auth-Number:w - - - - Name:w - Personal-name:w - Subject-name-personal:w - Subject:w - Subject:p - - - - Name-and-title:w - Subject:w - Subject:p - - - - Name-and-title:w - Title:w - Subject:w - Subject:p - - - - Koha-Auth-Number:w - - - - Name:w - Subject:w - Corporate-name:w - Subject:w - Subject:p - - - - Conference-name:w - Subject:w - Subject:p - - - - Name-and-title:w - Subject:w - Subject:p - - - - Name-and-title:w - Title:w - Subject:w - Subject:p - - - - Koha-Auth-Number:w - - - - Name:w - Subject:w - Subject:p - - - - Thematic-number:w - Subject:w - Subject:p - - - - Thematic-number:w - Subject:w - Subject:p - - - - Music-key:w - Subject:w - Subject:p - - - - Koha-Auth-Number:w - - - - Subject:w - Subject:p - - - Koha-Auth-Number:w - - - - Koha-Auth-Number:w - - - - Subject:w - Subject:p - - - - Koha-Auth-Number:w - - - - Name-geographic:w - Subject:w - Subject:p - - - - Koha-Auth-Number:w - - - - Koha-Auth-Number:w - - - - Subject:w - Subject:p - - - - Koha-Auth-Number:w - - - - Subject:w - Subject:p - - - - Koha-Auth-Number:w - - - - Subject:w - Subject:p - - - - Koha-Auth-Number:w - - - - Subject:w - Subject:p - - - - Koha-Auth-Number:w - - - - Subject:w - Subject:p - - - - Koha-Auth-Number:w - - - - Subject:w - Subject:p - - - - Cross-Reference:w - Koha-Auth-Number:w - - - - Author:w - Author:p - - - - Thematic-number:w - - - - Thematic-number:w - - - - Music-key:w - - - - Author-title:w - Name-and-title:w - Title:w - Title-uniform:w - - - - Author:w - Author-name-corporate:w - Author-name-personal:w - Name:w - Editor:w - Personal-name:w - - - - Author:w - Corporate-name:w - - - - Author-title:w - Name-and-title:w - Title:w - Title-uniform:w - - - - Name-and-title:w - - - - Thematic-number:w - - - - Koha-Auth-Number:w - - - - Author:w - Name:w - - - - Name-and-title:w - - - - Author-title:w - Title:w - Title-uniform:w - - - - Koha-Auth-Number:w - - - - Author-name-corporate:w - Name:w - Conference-name:w - - - - Thematic-number:w - - - - Thematic-number:w - - - - Music-key:w - - - - Koha-Auth-Number:w - - - - Title:w - Title-uniform:w - - - - Title:w - Title-other-variant:w - - - - Host-item:w - - - - Host-Item-Number:w - - - - Host-item:w - - - - Record-control-number:w - - - - Title:w - - - - Title:w - Title-former:w - Related-periodical:w - - - - Related-periodical:w - - - - Name-and-title:w - - - - Author-title:w - Name-and-title:w - Title:w - Title-series:w - - - - Koha-Auth-Number:w - - - - Author:w - Author-name-personal:w - Name:w - Personal-name:w - - - - Name-and-title:w - - - - Author-title:w - Name-and-title:w - Title:w - Title-series:w - - - - Koha-Auth-Number:w - - - - Author:w - Corporate-name:w - Author-name-corporate:w - Name:w - - - - Name-and-title:w - - - - Koha-Auth-Number:w - - - - Author-title:w - Name-and-title:w - Title:w - Title-series:w - - - - Author:w - Author-name-corporate:w - Name:w - Conference-name:w - - - - Koha-Auth-Number:w - - - - Title:w - Title-series:w - - - - Local-Number:n - Local-Number:w - Local-Number:s - - - - biblioitemnumber:n - biblioitemnumber:w - biblioitemnumber:s - - - - totalissues:n - totalissues:s - - - - cn-bib-source:w - - - - cn-bib-sort:n - cn-bib-sort:s - - - - itemtype:w - - - - Suppress:w - Suppress:n - - - - cn-class:w - - - - cn-item:w - - - - cn-prefix:w - - - - cn-suffix:w - - - - withdrawn:n - withdrawn:w - - - - lost:w - lost:n - - - - classification-source:w - - - - materials-specified:w - - - - damaged:n - damaged:w - - - - restricted:n - restricted:w - - - - cn-sort:n - cn-sort:s - - - - notforloan:n - notforloan:w - - - - ccode:w - - - - itemnumber:n - itemnumber:s - - - - homebranch:w - - - - holdingbranch:w - - - - location:w - - - - Date-of-acquisition:w - Date-of-acquisition:d - Date-of-acquisition:s - - - - acqsource:w - - - - coded-location-qualifier:w - - - - price:w - - - - stack:n - stack:w - - - - issues:n - issues:w - issues:s - - - - renewals:n - renewals:w - - - - reserves:n - reserves:w - - - - Local-classification:w - Local-classification:p - Local-classification:s - - - - barcode:w - barcode:n - - - - onloan:n - onloan:w - - - - datelastseen:w - - - - datelastborrowed:w - - - - copynumber:w - - - - uri:u - - - - replacementprice:w - - - - replacementpricedate:w - - - - itype:w - - - - not-onloan-count:n - - - - au:0 - - - au:0 - - - se:0 - - - >se:0 - - - su-ut:0 - - - su-to:0 - - - su-geo:0 - - - au:0 - - - itype:0 - - - homebranch:0 - - - holdingbranch:0 - - - location:0 - - - itype:0 - - - ccode:0 - - - diff --git a/etc/zebradb/marc_defs/normarc/biblios/biblio-zebra-indexdefs.xsl b/etc/zebradb/marc_defs/normarc/biblios/biblio-zebra-indexdefs.xsl deleted file mode 100644 index a7aae13203..0000000000 --- a/etc/zebradb/marc_defs/normarc/biblios/biblio-zebra-indexdefs.xsl +++ /dev/null @@ -1,1909 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/etc/zebradb/marc_defs/normarc/biblios/preprocess_marcxml.xsl b/etc/zebradb/marc_defs/normarc/biblios/preprocess_marcxml.xsl deleted file mode 100644 index 8140c0af59..0000000000 --- a/etc/zebradb/marc_defs/normarc/biblios/preprocess_marcxml.xsl +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/installer/data/mysql/db_revs/230600061.pl b/installer/data/mysql/db_revs/230600061.pl index cb1a47cdbf..a9bf4e4596 100755 --- a/installer/data/mysql/db_revs/230600061.pl +++ b/installer/data/mysql/db_revs/230600061.pl @@ -80,7 +80,7 @@ return { if ( !column_exists( 'items', 'bookable' ) ) { $dbh->do( q{ - ALTER TABLE items ADD COLUMN `bookable` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'boolean value defining whether this item is available for bookings or not' AFTER `barcode` + ALTER TABLE items ADD COLUMN `bookable` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'boolean value defining whether this this item is available for bookings or not' AFTER `barcode` } ); @@ -90,7 +90,7 @@ return { if ( !column_exists( 'deleteditems', 'bookable' ) ) { $dbh->do( q{ - ALTER TABLE deleteditems ADD COLUMN `bookable` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'boolean value defining whether this item is available for bookings or not' AFTER `barcode` + ALTER TABLE deleteditems ADD COLUMN `bookable` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'boolean value defining whether this this item is available for bookings or not' AFTER `barcode` } ); diff --git a/installer/data/mysql/db_revs/240505001.pl b/installer/data/mysql/db_revs/240505001.pl new file mode 100755 index 0000000000..5812382d4a --- /dev/null +++ b/installer/data/mysql/db_revs/240505001.pl @@ -0,0 +1,26 @@ +use Modern::Perl; +use Koha::Installer::Output qw(say_warning say_failure say_success say_info); + +return { + bug_number => "36822", + description => "Sanitize borrowers.updated_on", + up => sub { + my ($args) = @_; + my ( $dbh, $out ) = @$args{qw(dbh out)}; + + my $sth = $dbh->prepare( + q{ + SELECT borrowernumber + FROM borrowers + WHERE CAST(updated_on AS CHAR(19)) = '0000-00-00 00:00:00' + } + ); + $sth->execute; + my $results = $sth->fetchall_arrayref( {} ); + if (@$results) { + sanitize_zero_date( 'borrowers', 'updated_on' ); + say_info( $out, "The following borrowers' updated_on has been sanitized: " + . join( ', ', map { $_->{borrowernumber} } @$results ) ); + } + }, +}; diff --git a/installer/data/mysql/db_revs/240505002.pl b/installer/data/mysql/db_revs/240505002.pl new file mode 100755 index 0000000000..28f75a2fe5 --- /dev/null +++ b/installer/data/mysql/db_revs/240505002.pl @@ -0,0 +1,20 @@ +use Modern::Perl; +use Koha::Installer::Output qw(say_warning say_failure say_success say_info); + +return { + bug_number => "37757", + description => "More robust handling of EmailFieldPrimary syspref values", + up => sub { + my ($args) = @_; + my ( $dbh, $out ) = @$args{qw(dbh out)}; + + $dbh->do( + q{ + UPDATE systempreferences + SET value=IF(value='OFF','',value), + options='|email|emailpro|B_email|cardnumber|MULTI' + WHERE variable='EmailFieldPrimary'; + } + ) == 1 && say_success( $out, "Updated system preference 'EmailFieldPrimary'" ); + }, +}; diff --git a/installer/data/mysql/db_revs/240505003.pl b/installer/data/mysql/db_revs/240505003.pl new file mode 100755 index 0000000000..0fef0d3cd3 --- /dev/null +++ b/installer/data/mysql/db_revs/240505003.pl @@ -0,0 +1,23 @@ +use Modern::Perl; + +return { + bug_number => "37446", + description => "Fix holdingbranch and homebranch facet labels", + up => sub { + my ($args) = @_; + my ( $dbh, $out ) = @$args{qw(dbh out)}; + + # Do not update the label if different from the original one + my $sth = $dbh->prepare( + q{ + UPDATE search_field + SET label = ? + WHERE name = ? AND label = ? + } + ); + $sth->execute( 'Holding libraries', 'holdingbranch', 'holdinglibrary' ); + $sth->execute( 'Home libraries', 'homebranch', 'homelibrary' ); + + say $out "Updated search field configuration for holdingbranch and homebranch"; + }, +}; diff --git a/installer/data/mysql/db_revs/240505004.pl b/installer/data/mysql/db_revs/240505004.pl new file mode 100755 index 0000000000..1c75e5b3ed --- /dev/null +++ b/installer/data/mysql/db_revs/240505004.pl @@ -0,0 +1,44 @@ +use Modern::Perl; +use Koha::Installer::Output qw(say_warning say_failure say_success say_info); + +return { + bug_number => "37954", + description => "Move holdings_barcodes setting to holdings_barcode", + up => sub { + my ($args) = @_; + my ( $dbh, $out ) = @$args{qw(dbh out)}; + + my ($existing_holdings_barcode_setting) = $dbh->selectrow_array( + q{ + SELECT COUNT(*) FROM columns_settings WHERE module='catalogue' AND page='detail' AND tablename='holdings_table' AND columnname='holdings_barcode' + } + ); + if ($existing_holdings_barcode_setting) { + say_info( $out, "Settings already exist" ); + } else { + my ( $cannot_be_toggled, $is_hidden ) = $dbh->selectrow_array( + q{ + SELECT cannot_be_toggled,is_hidden FROM columns_settings WHERE module='catalogue' AND page='detail' AND tablename='holdings_table' AND columnname='holdings_barcodes' + } + ); + + if ( defined $cannot_be_toggled || defined $is_hidden ) { + $dbh->do( + qq{ + INSERT IGNORE INTO columns_settings VALUES + ('catalogue', 'detail', 'holdings_table', 'holdings_barcode', $cannot_be_toggled, $is_hidden ) + } + ); + say_success( $out, "Settings moved to holdings_barcode" ); + } else { + say_info( $out, "No settings for holdings_barcodes found" ); + } + } + $dbh->do( + q{ + DELETE FROM columns_settings WHERE module='catalogue' AND page='detail' AND tablename='holdings_table' AND columnname='holdings_barcodes' + } + ); + say $out "Removed settings for holdings_barcodes"; + }, +}; diff --git a/installer/data/mysql/db_revs/240505005.pl b/installer/data/mysql/db_revs/240505005.pl new file mode 100755 index 0000000000..9936d3b335 --- /dev/null +++ b/installer/data/mysql/db_revs/240505005.pl @@ -0,0 +1,13 @@ +use Modern::Perl; +use Koha::Installer::Output qw(say_warning say_failure say_success say_info); + +return { + bug_number => "38274", + description => "Fix typo in arabic language description", + up => sub { + my ($args) = @_; + my ( $dbh, $out ) = @$args{qw(dbh out)}; + + $dbh->do(q{ UPDATE language_descriptions SET description='العربية' WHERE subtag='ar' AND type='language' AND lang='ar' }); + }, +}; diff --git a/installer/data/mysql/db_revs/240505006.pl b/installer/data/mysql/db_revs/240505006.pl new file mode 100755 index 0000000000..80d7c842a1 --- /dev/null +++ b/installer/data/mysql/db_revs/240505006.pl @@ -0,0 +1,31 @@ +use Modern::Perl; +use Koha::Installer::Output qw(say_warning say_failure say_success say_info); + +return { + bug_number => "30648", + description => "Store biblionumber of deleted record in old reserves", + up => sub { + my ($args) = @_; + my ( $dbh, $out ) = @$args{qw(dbh out)}; + if ( !column_exists( 'reserves', 'deleted_biblionumber' ) ) { + + $dbh->do( + q{ + ALTER TABLE `reserves` + ADD COLUMN `deleted_biblionumber` int(11) NULL DEFAULT NULL COMMENT 'links the reserve to the deleted bibliographic record (deletedbiblio.biblionumber)' AFTER biblionumber + } + ); + } + say $out "Added column 'reserves.deleted_biblionumber'"; + if ( !column_exists( 'old_reserves', 'deleted_biblionumber' ) ) { + + $dbh->do( + q{ + ALTER TABLE `old_reserves` + ADD COLUMN `deleted_biblionumber` int(11) NULL DEFAULT NULL COMMENT 'links the reserve to the deleted bibliographic record (deletedbiblio.biblionumber)' AFTER biblionumber + } + ); + } + say $out "Added column 'old_reserves.deleted_biblionumber'"; + }, +}; diff --git a/installer/data/mysql/db_revs/240505007.pl b/installer/data/mysql/db_revs/240505007.pl new file mode 100755 index 0000000000..8544c30b5f --- /dev/null +++ b/installer/data/mysql/db_revs/240505007.pl @@ -0,0 +1,21 @@ +use Modern::Perl; +use Koha::Installer::Output qw(say_warning say_failure say_success say_info); + +return { + bug_number => "37856", + description => "Add service_platform column to erm_usage_data_providers", + up => sub { + my ($args) = @_; + my ( $dbh, $out ) = @$args{qw(dbh out)}; + + if ( !column_exists( 'erm_usage_data_providers', 'service_platform' ) ) { + $dbh->do( + q{ + ALTER TABLE erm_usage_data_providers ADD COLUMN `service_platform` varchar(80) DEFAULT NULL COMMENT 'platform if provider requires it' AFTER `report_types` + } + ); + say_info( $out, "Bug 37856 - Added service_platform column to table 'erm_usage_data_providers'" ); + } + say_success( $out, "Bug 37856 - Done" ); + }, +}; diff --git a/installer/data/mysql/db_revs/240505008.pl b/installer/data/mysql/db_revs/240505008.pl new file mode 100755 index 0000000000..934c0c6713 --- /dev/null +++ b/installer/data/mysql/db_revs/240505008.pl @@ -0,0 +1,20 @@ +use Modern::Perl; +use Koha::Installer::Output qw(say_warning say_success say_info); + +return { + bug_number => "37292", + description => "'oauth_access_tokens.expires' needs an index", + up => sub { + my ($args) = @_; + my ( $dbh, $out ) = @$args{qw(dbh out)}; + + if ( !index_exists( 'oauth_access_tokens', 'expires' ) ) { + $dbh->do( + q{ + ALTER TABLE `oauth_access_tokens` ADD INDEX `expires` (`expires`) + } + ); + say_success( $out, "Added new index on 'oauth_access_tokens.expires'" ); + } + }, +}; diff --git a/installer/data/mysql/db_revs/240505009.pl b/installer/data/mysql/db_revs/240505009.pl new file mode 100755 index 0000000000..2502fdca5d --- /dev/null +++ b/installer/data/mysql/db_revs/240505009.pl @@ -0,0 +1,14 @@ +use Modern::Perl; +use Koha::Installer::Output qw(say_warning say_success say_info); + +return { + bug_number => "38522", + description => "increase erm_agreements.license_info length", + up => sub { + my ($args) = @_; + my ( $dbh, $out ) = @$args{qw(dbh out)}; + + $dbh->do(q{ALTER TABLE erm_agreements MODIFY COLUMN license_info mediumtext DEFAULT NULL COMMENT 'info about the license'}); + say_success( $out, "Updated erm_agreements.license_info to mediumtext." ); + }, +}; diff --git a/installer/data/mysql/en/marcflavour/marc21/mandatory/marc21_framework_DEFAULT.yml b/installer/data/mysql/en/marcflavour/marc21/mandatory/marc21_framework_DEFAULT.yml index 88aafc1fee..bddc9a1025 100644 --- a/installer/data/mysql/en/marcflavour/marc21/mandatory/marc21_framework_DEFAULT.yml +++ b/installer/data/mysql/en/marcflavour/marc21/mandatory/marc21_framework_DEFAULT.yml @@ -2135,8 +2135,8 @@ tables: frameworkcode: "" - tagfield: "383" - liblibrarian: "NUMERIC DESIGNATION OF MUSICAL WORK" - libopac: "NUMERIC DESIGNATION OF MUSICAL WORK" + liblibrarian: "NUMERIC DESIGNATION OF MUSICAL WORK OR EXPRESSION" + libopac: "NUMERIC DESIGNATION OF MUSICAL WORK OR EXPRESSION" repeatable: 1 mandatory: 0 authorised_value: @@ -10000,6 +10000,42 @@ tables: link: "" defaultvalue: + - tagfield: "082" + tagsubfield: "0" + liblibrarian: "Authority record control number or standard number" + libopac: "Authority record control number or standard number" + repeatable: 1 + mandatory: 0 + kohafield: "" + tab: 0 + authorised_value: "" + authtypecode: "" + value_builder: "" + isurl: + hidden: -6 + frameworkcode: "" + seealso: "" + link: "" + defaultvalue: + + - tagfield: "082" + tagsubfield: "1" + liblibrarian: "Real World Object URI" + libopac: "Real World Object URI" + repeatable: 1 + mandatory: 0 + kohafield: "" + tab: 0 + authorised_value: "" + authtypecode: "" + value_builder: "" + isurl: + hidden: -6 + frameworkcode: "" + seealso: "" + link: "" + defaultvalue: + - tagfield: "082" tagsubfield: "2" liblibrarian: "Edition information" @@ -10144,6 +10180,42 @@ tables: link: "" defaultvalue: + - tagfield: "083" + tagsubfield: "0" + liblibrarian: "Authority record control number or standard number" + libopac: "Authority record control number or standard number" + repeatable: 1 + mandatory: 0 + kohafield: "" + tab: 0 + authorised_value: "" + authtypecode: "" + value_builder: "" + isurl: + hidden: -6 + frameworkcode: "" + seealso: "" + link: "" + defaultvalue: + + - tagfield: "083" + tagsubfield: "1" + liblibrarian: "Real World Object URI" + libopac: "Real World Object URI" + repeatable: 1 + mandatory: 0 + kohafield: "" + tab: 0 + authorised_value: "" + authtypecode: "" + value_builder: "" + isurl: + hidden: -6 + frameworkcode: "" + seealso: "" + link: "" + defaultvalue: + - tagfield: "083" tagsubfield: "2" liblibrarian: "Edition information" @@ -19162,6 +19234,42 @@ tables: link: "" defaultvalue: + - tagfield: "341" + tagsubfield: "0" + liblibrarian: "Authority record control number or standard number" + libopac: "Authority record control number or standard number" + repeatable: 1 + mandatory: 0 + kohafield: "" + tab: 3 + authorised_value: "" + authtypecode: "" + value_builder: "" + isurl: + hidden: -6 + frameworkcode: "" + seealso: "" + link: "" + defaultvalue: + + - tagfield: "341" + tagsubfield: "1" + liblibrarian: "Real World Object URI" + libopac: "Real World Object URI" + repeatable: 1 + mandatory: 0 + kohafield: "" + tab: 3 + authorised_value: "" + authtypecode: "" + value_builder: "" + isurl: + hidden: -6 + frameworkcode: "" + seealso: "" + link: "" + defaultvalue: + - tagfield: "341" tagsubfield: "2" liblibrarian: "Source" @@ -33724,6 +33832,24 @@ tables: link: "" defaultvalue: + - tagfield: "580" + tagsubfield: "5" + liblibrarian: "Institution to which field applies" + libopac: "Institution to which field applies" + repeatable: 0 + mandatory: 0 + kohafield: "" + tab: 5 + authorised_value: "" + authtypecode: "" + value_builder: "" + isurl: + hidden: -6 + frameworkcode: "" + seealso: "" + link: "" + defaultvalue: + - tagfield: "580" tagsubfield: "6" liblibrarian: "Linkage" @@ -37036,6 +37162,24 @@ tables: link: "" defaultvalue: + - tagfield: "647" + tagsubfield: "4" + liblibrarian: "Relationship" + libopac: "Relationship" + repeatable: 1 + mandatory: 0 + kohafield: "" + tab: 6 + authorised_value: "" + authtypecode: "" + value_builder: "" + isurl: + hidden: -6 + frameworkcode: "" + seealso: "" + link: "" + defaultvalue: + - tagfield: "647" tagsubfield: "6" liblibrarian: "Linkage" @@ -37072,6 +37216,24 @@ tables: link: "" defaultvalue: + - tagfield: "647" + tagsubfield: "e" + liblibrarian: "Relator term" + libopac: "Relator term" + repeatable: 1 + mandatory: 0 + kohafield: "" + tab: 6 + authorised_value: "" + authtypecode: "" + value_builder: "" + isurl: + hidden: -6 + frameworkcode: "" + seealso: "" + link: "" + defaultvalue: + - tagfield: "647" tagsubfield: "v" liblibrarian: "Form subdivision" @@ -37216,6 +37378,24 @@ tables: link: "" defaultvalue: + - tagfield: "648" + tagsubfield: "4" + liblibrarian: "Relationship" + libopac: "Relationship" + repeatable: 1 + mandatory: 0 + kohafield: "" + tab: 6 + authorised_value: "" + authtypecode: "" + value_builder: "" + isurl: + hidden: -6 + frameworkcode: "" + seealso: "" + link: "" + defaultvalue: + - tagfield: "648" tagsubfield: "6" liblibrarian: "Linkage" @@ -37306,6 +37486,24 @@ tables: link: "" defaultvalue: + - tagfield: "648" + tagsubfield: "e" + liblibrarian: "Relator term" + libopac: "Relator term" + repeatable: 1 + mandatory: 0 + kohafield: "" + tab: 6 + authorised_value: "" + authtypecode: "" + value_builder: "" + isurl: + hidden: 0 + frameworkcode: "" + seealso: "" + link: "" + defaultvalue: + - tagfield: "648" tagsubfield: "v" liblibrarian: "Form subdivision" @@ -49024,6 +49222,24 @@ tables: link: "" defaultvalue: + - tagfield: "773" + tagsubfield: "5" + liblibrarian: "Institution to which field applies" + libopac: "Institution to which field applies" + repeatable: 0 + mandatory: 0 + kohafield: + tab: 7 + authorised_value: + authtypecode: + value_builder: "" + isurl: + hidden: -6 + frameworkcode: "" + seealso: "" + link: "" + defaultvalue: + - tagfield: "773" tagsubfield: "6" liblibrarian: "Linkage" @@ -49492,6 +49708,24 @@ tables: link: "" defaultvalue: + - tagfield: "774" + tagsubfield: "5" + liblibrarian: "Institution to which field applies" + libopac: "Institution to which field applies" + repeatable: 0 + mandatory: 0 + kohafield: + tab: 7 + authorised_value: + authtypecode: + value_builder: "" + isurl: + hidden: -6 + frameworkcode: "" + seealso: "" + link: "" + defaultvalue: + - tagfield: "774" tagsubfield: "6" liblibrarian: "Linkage" @@ -52696,6 +52930,24 @@ tables: link: "" defaultvalue: + - tagfield: "787" + tagsubfield: "5" + liblibrarian: "Institution to which field applies" + libopac: "Institution to which field applies" + repeatable: 0 + mandatory: 0 + kohafield: + tab: 7 + authorised_value: + authtypecode: + value_builder: "" + isurl: + hidden: -6 + frameworkcode: "" + seealso: "" + link: "" + defaultvalue: + - tagfield: "787" tagsubfield: "6" liblibrarian: "Linkage" diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index 71ec8ff31c..dba807a5d8 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -2750,7 +2750,7 @@ CREATE TABLE `deleteditems` ( `biblionumber` int(11) NOT NULL DEFAULT 0 COMMENT 'foreign key from biblio table used to link this item to the right bib record', `biblioitemnumber` int(11) NOT NULL DEFAULT 0 COMMENT 'foreign key from the biblioitems table to link to item to additional information', `barcode` varchar(20) DEFAULT NULL COMMENT 'item barcode (MARC21 952$p)', - `bookable` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'boolean value defining whether this item is available for bookings or not', + `bookable` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'boolean value defining whether this this item is available for bookings or not', `dateaccessioned` date DEFAULT NULL COMMENT 'date the item was acquired or added to Koha (MARC21 952$d)', `booksellerid` longtext DEFAULT NULL COMMENT 'where the item was purchased (MARC21 952$e)', `homebranch` varchar(10) DEFAULT NULL COMMENT 'foreign key from the branches table for the library that owns this item (MARC21 952$a)', @@ -2966,7 +2966,7 @@ CREATE TABLE `erm_agreements` ( `closure_reason` varchar(80) DEFAULT NULL COMMENT 'reason of the closure', `is_perpetual` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'is the agreement perpetual', `renewal_priority` varchar(80) DEFAULT NULL COMMENT 'priority of the renewal', - `license_info` varchar(80) DEFAULT NULL COMMENT 'info about the license', + `license_info` mediumtext DEFAULT NULL COMMENT 'info about the license', PRIMARY KEY (`agreement_id`), KEY `erm_agreements_ibfk_1` (`vendor_id`), CONSTRAINT `erm_agreements_ibfk_1` FOREIGN KEY (`vendor_id`) REFERENCES `aqbooksellers` (`id`) ON DELETE SET NULL ON UPDATE CASCADE @@ -3211,6 +3211,7 @@ CREATE TABLE `erm_usage_data_providers` ( `requestor_name` varchar(80) DEFAULT NULL COMMENT 'requestor name', `requestor_email` varchar(80) DEFAULT NULL COMMENT 'requestor email', `report_types` varchar(255) DEFAULT NULL COMMENT 'report types provided by the harvester', + `service_platform` varchar(80) DEFAULT NULL COMMENT 'platform if provider requires it', PRIMARY KEY (`erm_usage_data_provider_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; @@ -4008,7 +4009,7 @@ CREATE TABLE `items` ( `biblionumber` int(11) NOT NULL DEFAULT 0 COMMENT 'foreign key from biblio table used to link this item to the right bib record', `biblioitemnumber` int(11) NOT NULL DEFAULT 0 COMMENT 'foreign key from the biblioitems table to link to item to additional information', `barcode` varchar(20) DEFAULT NULL COMMENT 'item barcode (MARC21 952$p)', - `bookable` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'boolean value defining whether this item is available for bookings or not', + `bookable` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'boolean value defining whether this this item is available for bookings or not', `dateaccessioned` date DEFAULT NULL COMMENT 'date the item was acquired or added to Koha (MARC21 952$d)', `booksellerid` longtext DEFAULT NULL COMMENT 'where the item was purchased (MARC21 952$e)', `homebranch` varchar(10) DEFAULT NULL COMMENT 'foreign key from the branches table for the library that owns this item (MARC21 952$a)', @@ -4862,7 +4863,8 @@ CREATE TABLE `oauth_access_tokens` ( `access_token` varchar(191) NOT NULL COMMENT 'generarated access token', `client_id` varchar(191) NOT NULL COMMENT 'the client id the access token belongs to', `expires` int(11) NOT NULL COMMENT 'expiration time in seconds', - PRIMARY KEY (`access_token`) + PRIMARY KEY (`access_token`), + KEY `expires` (`expires`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; @@ -4916,6 +4918,7 @@ CREATE TABLE `old_reserves` ( `borrowernumber` int(11) DEFAULT NULL COMMENT 'foreign key from the borrowers table defining which patron this hold is for', `reservedate` date DEFAULT NULL COMMENT 'the date the hold was places', `biblionumber` int(11) DEFAULT NULL COMMENT 'foreign key from the biblio table defining which bib record this hold is on', + `deleted_biblionumber` int(11) DEFAULT NULL COMMENT 'links the hold to the deleted bibliographic record (deletedbiblio.biblionumber)', `item_group_id` int(11) DEFAULT NULL COMMENT 'foreign key from the item_groups table defining if this is an item group level hold', `branchcode` varchar(10) DEFAULT NULL COMMENT 'foreign key from the branches table defining which branch the patron wishes to pick this hold up at', `desk_id` int(11) DEFAULT NULL COMMENT 'foreign key from the desks table defining which desk the patron should pick this hold up at', @@ -5485,6 +5488,7 @@ CREATE TABLE `reserves` ( `borrowernumber` int(11) NOT NULL DEFAULT 0 COMMENT 'foreign key from the borrowers table defining which patron this hold is for', `reservedate` date DEFAULT NULL COMMENT 'the date the hold was placed', `biblionumber` int(11) NOT NULL DEFAULT 0 COMMENT 'foreign key from the biblio table defining which bib record this hold is on', + `deleted_biblionumber` int(11) DEFAULT NULL COMMENT 'links the hold to the deleted bibliographic record (deletedbiblio.biblionumber)', `item_group_id` int(11) DEFAULT NULL COMMENT 'foreign key from the item_groups table defining if this is an item group level hold', `branchcode` varchar(10) NOT NULL COMMENT 'foreign key from the branches table defining which branch the patron wishes to pick this hold up at', `desk_id` int(11) DEFAULT NULL COMMENT 'foreign key from the desks table defining which desk the patron should pick this hold up at', diff --git a/installer/data/mysql/mandatory/keyboard_shortcuts.sql b/installer/data/mysql/mandatory/keyboard_shortcuts.sql index 3179d30880..e9caf9c008 100644 --- a/installer/data/mysql/mandatory/keyboard_shortcuts.sql +++ b/installer/data/mysql/mandatory/keyboard_shortcuts.sql @@ -33,7 +33,7 @@ INSERT INTO keyboard_shortcuts (shortcut_name, shortcut_keys) VALUES ("next_position","Tab"), ("prev_position","Shift-Tab"), ("toggle_keyboard", "Shift-Ctrl-K"), - ("copy_line","Ctrl-C"), + ("copy_line","Ctrl-Alt-C"), ("copy_subfield","Shift-Ctrl-C"), ("paste_line","Ctrl-P"), ("insert_line","Ctrl-I"); diff --git a/installer/data/mysql/mandatory/subtag_registry.sql b/installer/data/mysql/mandatory/subtag_registry.sql index 671c08bff3..6a052965ce 100644 --- a/installer/data/mysql/mandatory/subtag_registry.sql +++ b/installer/data/mysql/mandatory/subtag_registry.sql @@ -83,7 +83,7 @@ INSERT INTO language_rfc4646_to_iso639(rfc4646_subtag,iso639_2_code) VALUES ( 'ar','ara'); INSERT INTO language_descriptions(subtag, type, lang, description) -VALUES ( 'ar', 'language', 'ar', 'لعربية'); +VALUES ( 'ar', 'language', 'ar', 'العربية'); INSERT INTO language_descriptions(subtag, type, lang, description) VALUES ( 'ar', 'language', 'en', 'Arabic'); diff --git a/installer/data/mysql/mandatory/sysprefs.sql b/installer/data/mysql/mandatory/sysprefs.sql index b64242c791..6eac0c413d 100644 --- a/installer/data/mysql/mandatory/sysprefs.sql +++ b/installer/data/mysql/mandatory/sysprefs.sql @@ -233,7 +233,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('EmailAddressForPatronRegistrations', '', '', ' If you choose EmailAddressForPatronRegistrations you have to enter a valid email address: ', 'free'), ('EmailAddressForSuggestions','','',' If you choose EmailAddressForSuggestions you have to enter a valid email address: ','free'), ('EmailFieldPrecedence','email|emailpro|B_email','','Ordered list of patron email fields to use when AutoEmailPrimaryAddress is set to first valid','multiple'), -('EmailFieldPrimary','OFF','email|emailpro|B_email|cardnumber|OFF|MULTI','Defines the default email address field where patron email notices are sent.','Choice'), +('EmailFieldPrimary','','|email|emailpro|B_email|cardnumber|MULTI','Defines the default email address field where patron email notices are sent.','Choice'), ('EmailFieldSelection','','email|emailpro|B_email','Selection list of patron email fields to use whern AutoEmailPrimaryAddress is set to selected addresses','multiple'), ('emailLibrarianWhenHoldIsPlaced','0',NULL,'If ON, emails the librarian whenever a hold is placed','YesNo'), ('EmailOverduesNoEmail','1',NULL,'Send send overdues of patrons without email address to staff','YesNo'), diff --git a/koha-tmpl/intranet-tmpl/lib/datatables/datatables.js b/koha-tmpl/intranet-tmpl/lib/datatables/datatables.js index d5de7e72f7..a8ecb4bde3 100644 --- a/koha-tmpl/intranet-tmpl/lib/datatables/datatables.js +++ b/koha-tmpl/intranet-tmpl/lib/datatables/datatables.js @@ -100635,7 +100635,7 @@ this.pdfMake = this.pdfMake || {}; this.pdfMake.vfs = { // on destroy, while the `dt` namespaced event is the one we are // listening for $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { - if ( settings !== ctx ) { // need to check this is the host + if ( settings !== ctx ) { // need to check this this is the host return; // table, not a nested one } diff --git a/koha-tmpl/intranet-tmpl/lib/jquery/plugins/jszip.min.js b/koha-tmpl/intranet-tmpl/lib/jquery/plugins/jszip.min.js deleted file mode 100644 index 218a4f7d6c..0000000000 --- a/koha-tmpl/intranet-tmpl/lib/jquery/plugins/jszip.min.js +++ /dev/null @@ -1,15 +0,0 @@ -/*! - -JSZip v3.1.3 - A Javascript class for generating and reading zip files - - -(c) 2009-2016 Stuart Knightley -Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. - -JSZip uses the library pako released under the MIT license : -https://github.com/nodeca/pako/blob/master/LICENSE -*/ -!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.JSZip=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g>2,h=(3&b)<<4|c>>4,i=n>1?(15&c)<<2|e>>6:64,j=n>2?63&e:64,k.push(f.charAt(g)+f.charAt(h)+f.charAt(i)+f.charAt(j));return k.join("")},c.decode=function(a){var b,c,d,g,h,i,j,k=0,l=0,m="data:";if(a.substr(0,m.length)===m)throw new Error("Invalid base64 input, it looks like a data url.");a=a.replace(/[^A-Za-z0-9\+\/\=]/g,"");var n=3*a.length/4;if(a.charAt(a.length-1)===f.charAt(64)&&n--,a.charAt(a.length-2)===f.charAt(64)&&n--,n%1!==0)throw new Error("Invalid base64 input, bad content length.");var o;for(o=e.uint8array?new Uint8Array(0|n):new Array(0|n);k>4,c=(15&h)<<4|i>>2,d=(3&i)<<6|j,o[l++]=b,64!==i&&(o[l++]=c),64!==j&&(o[l++]=d);return o}},{"./support":30,"./utils":32}],2:[function(a,b,c){"use strict";function d(a,b,c,d,e){this.compressedSize=a,this.uncompressedSize=b,this.crc32=c,this.compression=d,this.compressedContent=e}var e=a("./external"),f=a("./stream/DataWorker"),g=a("./stream/DataLengthProbe"),h=a("./stream/Crc32Probe"),g=a("./stream/DataLengthProbe");d.prototype={getContentWorker:function(){var a=new f(e.Promise.resolve(this.compressedContent)).pipe(this.compression.uncompressWorker()).pipe(new g("data_length")),b=this;return a.on("end",function(){if(this.streamInfo.data_length!==b.uncompressedSize)throw new Error("Bug : uncompressed data size mismatch")}),a},getCompressedWorker:function(){return new f(e.Promise.resolve(this.compressedContent)).withStreamInfo("compressedSize",this.compressedSize).withStreamInfo("uncompressedSize",this.uncompressedSize).withStreamInfo("crc32",this.crc32).withStreamInfo("compression",this.compression)}},d.createWorkerFrom=function(a,b,c){return a.pipe(new h).pipe(new g("uncompressedSize")).pipe(b.compressWorker(c)).pipe(new g("compressedSize")).withStreamInfo("compression",b)},b.exports=d},{"./external":6,"./stream/Crc32Probe":25,"./stream/DataLengthProbe":26,"./stream/DataWorker":27}],3:[function(a,b,c){"use strict";var d=a("./stream/GenericWorker");c.STORE={magic:"\0\0",compressWorker:function(a){return new d("STORE compression")},uncompressWorker:function(){return new d("STORE decompression")}},c.DEFLATE=a("./flate")},{"./flate":7,"./stream/GenericWorker":28}],4:[function(a,b,c){"use strict";function d(){for(var a,b=[],c=0;c<256;c++){a=c;for(var d=0;d<8;d++)a=1&a?3988292384^a>>>1:a>>>1;b[c]=a}return b}function e(a,b,c,d){var e=h,f=d+c;a^=-1;for(var g=d;g>>8^e[255&(a^b[g])];return a^-1}function f(a,b,c,d){var e=h,f=d+c;a^=-1;for(var g=d;g>>8^e[255&(a^b.charCodeAt(g))];return a^-1}var g=a("./utils"),h=d();b.exports=function(a,b){if("undefined"==typeof a||!a.length)return 0;var c="string"!==g.getTypeOf(a);return c?e(0|b,a,a.length,0):f(0|b,a,a.length,0)}},{"./utils":32}],5:[function(a,b,c){"use strict";c.base64=!1,c.binary=!1,c.dir=!1,c.createFolders=!0,c.date=null,c.compression=null,c.compressionOptions=null,c.comment=null,c.unixPermissions=null,c.dosPermissions=null},{}],6:[function(a,b,c){"use strict";var d=null;d="undefined"!=typeof Promise?Promise:a("lie"),b.exports={Promise:d}},{lie:58}],7:[function(a,b,c){"use strict";function d(a,b){h.call(this,"FlateWorker/"+a),this._pako=new f[a]({raw:!0,level:b.level||-1}),this.meta={};var c=this;this._pako.onData=function(a){c.push({data:a,meta:c.meta})}}var e="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,f=a("pako"),g=a("./utils"),h=a("./stream/GenericWorker"),i=e?"uint8array":"array";c.magic="\b\0",g.inherits(d,h),d.prototype.processChunk=function(a){this.meta=a.meta,this._pako.push(g.transformTo(i,a.data),!1)},d.prototype.flush=function(){h.prototype.flush.call(this),this._pako.push([],!0)},d.prototype.cleanUp=function(){h.prototype.cleanUp.call(this),this._pako=null},c.compressWorker=function(a){return new d("Deflate",a)},c.uncompressWorker=function(){return new d("Inflate",{})}},{"./stream/GenericWorker":28,"./utils":32,pako:59}],8:[function(a,b,c){"use strict";function d(a,b,c,d){f.call(this,"ZipFileWorker"),this.bytesWritten=0,this.zipComment=b,this.zipPlatform=c,this.encodeFileName=d,this.streamFiles=a,this.accumulate=!1,this.contentBuffer=[],this.dirRecords=[],this.currentSourceOffset=0,this.entriesCount=0,this.currentFile=null,this._sources=[]}var e=a("../utils"),f=a("../stream/GenericWorker"),g=a("../utf8"),h=a("../crc32"),i=a("../signature"),j=function(a,b){var c,d="";for(c=0;c>>=8;return d},k=function(a,b){var c=a;return a||(c=b?16893:33204),(65535&c)<<16},l=function(a,b){return 63&(a||0)},m=function(a,b,c,d,f,m){var n,o,p=a.file,q=a.compression,r=m!==g.utf8encode,s=e.transformTo("string",m(p.name)),t=e.transformTo("string",g.utf8encode(p.name)),u=p.comment,v=e.transformTo("string",m(u)),w=e.transformTo("string",g.utf8encode(u)),x=t.length!==p.name.length,y=w.length!==u.length,z="",A="",B="",C=p.dir,D=p.date,E={crc32:0,compressedSize:0,uncompressedSize:0};b&&!c||(E.crc32=a.crc32,E.compressedSize=a.compressedSize,E.uncompressedSize=a.uncompressedSize);var F=0;b&&(F|=8),r||!x&&!y||(F|=2048);var G=0,H=0;C&&(G|=16),"UNIX"===f?(H=798,G|=k(p.unixPermissions,C)):(H=20,G|=l(p.dosPermissions,C)),n=D.getUTCHours(),n<<=6,n|=D.getUTCMinutes(),n<<=5,n|=D.getUTCSeconds()/2,o=D.getUTCFullYear()-1980,o<<=4,o|=D.getUTCMonth()+1,o<<=5,o|=D.getUTCDate(),x&&(A=j(1,1)+j(h(s),4)+t,z+="up"+j(A.length,2)+A),y&&(B=j(1,1)+j(h(v),4)+w,z+="uc"+j(B.length,2)+B);var I="";I+="\n\0",I+=j(F,2),I+=q.magic,I+=j(n,2),I+=j(o,2),I+=j(E.crc32,4),I+=j(E.compressedSize,4),I+=j(E.uncompressedSize,4),I+=j(s.length,2),I+=j(z.length,2);var J=i.LOCAL_FILE_HEADER+I+s+z,K=i.CENTRAL_FILE_HEADER+j(H,2)+I+j(v.length,2)+"\0\0\0\0"+j(G,4)+j(d,4)+s+z+v;return{fileRecord:J,dirRecord:K}},n=function(a,b,c,d,f){var g="",h=e.transformTo("string",f(d));return g=i.CENTRAL_DIRECTORY_END+"\0\0\0\0"+j(a,2)+j(a,2)+j(b,4)+j(c,4)+j(h.length,2)+h},o=function(a){var b="";return b=i.DATA_DESCRIPTOR+j(a.crc32,4)+j(a.compressedSize,4)+j(a.uncompressedSize,4)};e.inherits(d,f),d.prototype.push=function(a){var b=a.meta.percent||0,c=this.entriesCount,d=this._sources.length;this.accumulate?this.contentBuffer.push(a):(this.bytesWritten+=a.data.length,f.prototype.push.call(this,{data:a.data,meta:{currentFile:this.currentFile,percent:c?(b+100*(c-d-1))/c:100}}))},d.prototype.openedSource=function(a){this.currentSourceOffset=this.bytesWritten,this.currentFile=a.file.name;var b=this.streamFiles&&!a.file.dir;if(b){var c=m(a,b,!1,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);this.push({data:c.fileRecord,meta:{percent:0}})}else this.accumulate=!0},d.prototype.closedSource=function(a){this.accumulate=!1;var b=this.streamFiles&&!a.file.dir,c=m(a,b,!0,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);if(this.dirRecords.push(c.dirRecord),b)this.push({data:o(a),meta:{percent:100}});else for(this.push({data:c.fileRecord,meta:{percent:0}});this.contentBuffer.length;)this.push(this.contentBuffer.shift());this.currentFile=null},d.prototype.flush=function(){for(var a=this.bytesWritten,b=0;b0?a.substring(0,b):""},q=function(a){return"/"!==a.slice(-1)&&(a+="/"),a},r=function(a,b){return b="undefined"!=typeof b?b:i.createFolders,a=q(a),this.files[a]||o.call(this,a,null,{dir:!0,createFolders:b}),this.files[a]},s={load:function(){throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.")},forEach:function(a){var b,c,d;for(b in this.files)this.files.hasOwnProperty(b)&&(d=this.files[b],c=b.slice(this.root.length,b.length),c&&b.slice(0,this.root.length)===this.root&&a(c,d))},filter:function(a){var b=[];return this.forEach(function(c,d){a(c,d)&&b.push(d)}),b},file:function(a,b,c){if(1===arguments.length){if(d(a)){var e=a;return this.filter(function(a,b){return!b.dir&&e.test(a)})}var f=this.files[this.root+a];return f&&!f.dir?f:null}return a=this.root+a,o.call(this,a,b,c),this},folder:function(a){if(!a)return this;if(d(a))return this.filter(function(b,c){return c.dir&&a.test(b)});var b=this.root+a,c=r.call(this,b),e=this.clone();return e.root=c.name,e},remove:function(a){a=this.root+a;var b=this.files[a];if(b||("/"!==a.slice(-1)&&(a+="/"),b=this.files[a]),b&&!b.dir)delete this.files[a];else for(var c=this.filter(function(b,c){return c.name.slice(0,a.length)===a}),d=0;d=0;--f)if(this.data[f]===b&&this.data[f+1]===c&&this.data[f+2]===d&&this.data[f+3]===e)return f-this.zero;return-1},d.prototype.readAndCheckSignature=function(a){var b=a.charCodeAt(0),c=a.charCodeAt(1),d=a.charCodeAt(2),e=a.charCodeAt(3),f=this.readData(4);return b===f[0]&&c===f[1]&&d===f[2]&&e===f[3]},d.prototype.readData=function(a){if(this.checkOffset(a),0===a)return[];var b=this.data.slice(this.zero+this.index,this.zero+this.index+a);return this.index+=a,b},b.exports=d},{"../utils":32,"./DataReader":18}],18:[function(a,b,c){"use strict";function d(a){this.data=a,this.length=a.length,this.index=0,this.zero=0}var e=a("../utils");d.prototype={checkOffset:function(a){this.checkIndex(this.index+a)},checkIndex:function(a){if(this.length=this.index;b--)c=(c<<8)+this.byteAt(b);return this.index+=a,c},readString:function(a){return e.transformTo("string",this.readData(a))},readData:function(a){},lastIndexOfSignature:function(a){},readAndCheckSignature:function(a){},readDate:function(){var a=this.readInt(4);return new Date(Date.UTC((a>>25&127)+1980,(a>>21&15)-1,a>>16&31,a>>11&31,a>>5&63,(31&a)<<1))}},b.exports=d},{"../utils":32}],19:[function(a,b,c){"use strict";function d(a){e.call(this,a)}var e=a("./Uint8ArrayReader"),f=a("../utils");f.inherits(d,e),d.prototype.readData=function(a){this.checkOffset(a);var b=this.data.slice(this.zero+this.index,this.zero+this.index+a);return this.index+=a,b},b.exports=d},{"../utils":32,"./Uint8ArrayReader":21}],20:[function(a,b,c){"use strict";function d(a){e.call(this,a)}var e=a("./DataReader"),f=a("../utils");f.inherits(d,e),d.prototype.byteAt=function(a){return this.data.charCodeAt(this.zero+a)},d.prototype.lastIndexOfSignature=function(a){return this.data.lastIndexOf(a)-this.zero},d.prototype.readAndCheckSignature=function(a){var b=this.readData(4);return a===b},d.prototype.readData=function(a){this.checkOffset(a);var b=this.data.slice(this.zero+this.index,this.zero+this.index+a);return this.index+=a,b},b.exports=d},{"../utils":32,"./DataReader":18}],21:[function(a,b,c){"use strict";function d(a){e.call(this,a)}var e=a("./ArrayReader"),f=a("../utils");f.inherits(d,e),d.prototype.readData=function(a){if(this.checkOffset(a),0===a)return new Uint8Array(0);var b=this.data.subarray(this.zero+this.index,this.zero+this.index+a);return this.index+=a,b},b.exports=d},{"../utils":32,"./ArrayReader":17}],22:[function(a,b,c){"use strict";var d=a("../utils"),e=a("../support"),f=a("./ArrayReader"),g=a("./StringReader"),h=a("./NodeBufferReader"),i=a("./Uint8ArrayReader");b.exports=function(a){var b=d.getTypeOf(a);return d.checkSupport(b),"string"!==b||e.uint8array?"nodebuffer"===b?new h(a):e.uint8array?new i(d.transformTo("uint8array",a)):new f(d.transformTo("array",a)):new g(a)}},{"../support":30,"../utils":32,"./ArrayReader":17,"./NodeBufferReader":19,"./StringReader":20,"./Uint8ArrayReader":21}],23:[function(a,b,c){"use strict";c.LOCAL_FILE_HEADER="PK",c.CENTRAL_FILE_HEADER="PK",c.CENTRAL_DIRECTORY_END="PK",c.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",c.ZIP64_CENTRAL_DIRECTORY_END="PK",c.DATA_DESCRIPTOR="PK\b"},{}],24:[function(a,b,c){"use strict";function d(a){e.call(this,"ConvertWorker to "+a),this.destType=a}var e=a("./GenericWorker"),f=a("../utils");f.inherits(d,e),d.prototype.processChunk=function(a){this.push({data:f.transformTo(this.destType,a.data),meta:a.meta})},b.exports=d},{"../utils":32,"./GenericWorker":28}],25:[function(a,b,c){"use strict";function d(){e.call(this,"Crc32Probe"),this.withStreamInfo("crc32",0)}var e=a("./GenericWorker"),f=a("../crc32"),g=a("../utils");g.inherits(d,e),d.prototype.processChunk=function(a){this.streamInfo.crc32=f(a.data,this.streamInfo.crc32||0),this.push(a)},b.exports=d},{"../crc32":4,"../utils":32,"./GenericWorker":28}],26:[function(a,b,c){"use strict";function d(a){f.call(this,"DataLengthProbe for "+a),this.propName=a,this.withStreamInfo(a,0)}var e=a("../utils"),f=a("./GenericWorker");e.inherits(d,f),d.prototype.processChunk=function(a){if(a){var b=this.streamInfo[this.propName]||0;this.streamInfo[this.propName]=b+a.data.length}f.prototype.processChunk.call(this,a)},b.exports=d},{"../utils":32,"./GenericWorker":28}],27:[function(a,b,c){"use strict";function d(a){f.call(this,"DataWorker");var b=this;this.dataIsReady=!1,this.index=0,this.max=0,this.data=null,this.type="",this._tickScheduled=!1,a.then(function(a){b.dataIsReady=!0,b.data=a,b.max=a&&a.length||0,b.type=e.getTypeOf(a),b.isPaused||b._tickAndRepeat()},function(a){b.error(a)})}var e=a("../utils"),f=a("./GenericWorker"),g=16384;e.inherits(d,f),d.prototype.cleanUp=function(){f.prototype.cleanUp.call(this),this.data=null},d.prototype.resume=function(){return!!f.prototype.resume.call(this)&&(!this._tickScheduled&&this.dataIsReady&&(this._tickScheduled=!0,e.delay(this._tickAndRepeat,[],this)),!0)},d.prototype._tickAndRepeat=function(){this._tickScheduled=!1,this.isPaused||this.isFinished||(this._tick(),this.isFinished||(e.delay(this._tickAndRepeat,[],this),this._tickScheduled=!0))},d.prototype._tick=function(){if(this.isPaused||this.isFinished)return!1;var a=g,b=null,c=Math.min(this.max,this.index+a);if(this.index>=this.max)return this.end();switch(this.type){case"string":b=this.data.substring(this.index,c);break;case"uint8array":b=this.data.subarray(this.index,c);break;case"array":case"nodebuffer":b=this.data.slice(this.index,c)}return this.index=c,this.push({data:b,meta:{percent:this.max?this.index/this.max*100:0}})},b.exports=d},{"../utils":32,"./GenericWorker":28}],28:[function(a,b,c){"use strict";function d(a){this.name=a||"default",this.streamInfo={},this.generatedError=null,this.extraStreamInfo={},this.isPaused=!0,this.isFinished=!1,this.isLocked=!1,this._listeners={data:[],end:[],error:[]},this.previous=null}d.prototype={push:function(a){this.emit("data",a)},end:function(){if(this.isFinished)return!1;this.flush();try{this.emit("end"),this.cleanUp(),this.isFinished=!0}catch(a){this.emit("error",a)}return!0},error:function(a){return!this.isFinished&&(this.isPaused?this.generatedError=a:(this.isFinished=!0,this.emit("error",a),this.previous&&this.previous.error(a),this.cleanUp()),!0)},on:function(a,b){return this._listeners[a].push(b),this},cleanUp:function(){this.streamInfo=this.generatedError=this.extraStreamInfo=null,this._listeners=[]},emit:function(a,b){if(this._listeners[a])for(var c=0;c "+a:a}},b.exports=d},{}],29:[function(a,b,c){"use strict";function d(a,b,c,d){var f=null;switch(a){case"blob":return h.newBlob(c,d);case"base64":return f=e(b,c),k.encode(f);default:return f=e(b,c),h.transformTo(a,f)}}function e(a,b){var c,d=0,e=null,f=0;for(c=0;c=252?6:k>=248?5:k>=240?4:k>=224?3:k>=192?2:1;j[254]=j[254]=1;var l=function(a){var b,c,d,e,f,h=a.length,i=0;for(e=0;e>>6,b[f++]=128|63&c):c<65536?(b[f++]=224|c>>>12,b[f++]=128|c>>>6&63,b[f++]=128|63&c):(b[f++]=240|c>>>18,b[f++]=128|c>>>12&63,b[f++]=128|c>>>6&63,b[f++]=128|63&c);return b},m=function(a,b){var c;for(b=b||a.length,b>a.length&&(b=a.length),c=b-1;c>=0&&128===(192&a[c]);)c--;return c<0?b:0===c?b:c+j[a[c]]>b?c:b},n=function(a){var b,c,d,e,g=a.length,h=new Array(2*g);for(c=0,b=0;b4)h[c++]=65533,b+=e-1;else{for(d&=2===e?31:3===e?15:7;e>1&&b1?h[c++]=65533:d<65536?h[c++]=d:(d-=65536,h[c++]=55296|d>>10&1023,h[c++]=56320|1023&d)}return h.length!==c&&(h.subarray?h=h.subarray(0,c):h.length=c),f.applyFromCharCode(h)};c.utf8encode=function(a){return g.nodebuffer?h.newBuffer(a,"utf-8"):l(a)},c.utf8decode=function(a){return g.nodebuffer?f.transformTo("nodebuffer",a).toString("utf-8"):(a=f.transformTo(g.uint8array?"uint8array":"array",a),n(a))},f.inherits(d,i),d.prototype.processChunk=function(a){var b=f.transformTo(g.uint8array?"uint8array":"array",a.data);if(this.leftOver&&this.leftOver.length){if(g.uint8array){var d=b;b=new Uint8Array(d.length+this.leftOver.length),b.set(this.leftOver,0),b.set(d,this.leftOver.length)}else b=this.leftOver.concat(b);this.leftOver=null}var e=m(b),h=b;e!==b.length&&(g.uint8array?(h=b.subarray(0,e),this.leftOver=b.subarray(e,b.length)):(h=b.slice(0,e),this.leftOver=b.slice(e,b.length))),this.push({data:c.utf8decode(h),meta:a.meta})},d.prototype.flush=function(){this.leftOver&&this.leftOver.length&&(this.push({data:c.utf8decode(this.leftOver),meta:{}}),this.leftOver=null)},c.Utf8DecodeWorker=d,f.inherits(e,i),e.prototype.processChunk=function(a){this.push({data:c.utf8encode(a.data),meta:a.meta})},c.Utf8EncodeWorker=e},{"./nodejsUtils":14,"./stream/GenericWorker":28,"./support":30,"./utils":32}],32:[function(a,b,c){"use strict";function d(a){var b=null;return b=i.uint8array?new Uint8Array(a.length):new Array(a.length),f(a,b)}function e(a){return a}function f(a,b){for(var c=0;c1;)try{return n.stringifyByChunk(a,d,b)}catch(f){b=Math.floor(b/2)}return n.stringifyByChar(a)}function h(a,b){for(var c=0;c1)throw new Error("Multi-volumes zip are not supported")},readLocalFiles:function(){var a,b;for(a=0;a0)this.isSignature(c,g.CENTRAL_FILE_HEADER)||(this.reader.zero=e);else if(e<0)throw new Error("Corrupted zip: missing "+Math.abs(e)+" bytes.")},prepareReader:function(a){this.reader=e(a)},load:function(a){this.prepareReader(a),this.readEndOfCentral(),this.readCentralDir(),this.readLocalFiles()}},b.exports=d},{"./reader/readerFor":22,"./signature":23,"./support":30,"./utf8":31,"./utils":32,"./zipEntry":34}],34:[function(a,b,c){"use strict";function d(a,b){this.options=a,this.loadOptions=b}var e=a("./reader/readerFor"),f=a("./utils"),g=a("./compressedObject"),h=a("./crc32"),i=a("./utf8"),j=a("./compressions"),k=a("./support"),l=0,m=3,n=function(a){for(var b in j)if(j.hasOwnProperty(b)&&j[b].magic===a)return j[b];return null};d.prototype={isEncrypted:function(){return 1===(1&this.bitFlag)},useUTF8:function(){return 2048===(2048&this.bitFlag)},readLocalPart:function(a){var b,c;if(a.skip(22),this.fileNameLength=a.readInt(2),c=a.readInt(2),this.fileName=a.readData(this.fileNameLength),a.skip(c),this.compressedSize===-1||this.uncompressedSize===-1)throw new Error("Bug or corrupted zip : didn't get enough informations from the central directory (compressedSize === -1 || uncompressedSize === -1)");if(b=n(this.compressionMethod),null===b)throw new Error("Corrupted zip : compression "+f.pretty(this.compressionMethod)+" unknown (inner file : "+f.transformTo("string",this.fileName)+")");this.decompressed=new g(this.compressedSize,this.uncompressedSize,this.crc32,b,a.readData(this.compressedSize))},readCentralPart:function(a){this.versionMadeBy=a.readInt(2),a.skip(2),this.bitFlag=a.readInt(2),this.compressionMethod=a.readString(2),this.date=a.readDate(),this.crc32=a.readInt(4),this.compressedSize=a.readInt(4),this.uncompressedSize=a.readInt(4);var b=a.readInt(2);if(this.extraFieldsLength=a.readInt(2),this.fileCommentLength=a.readInt(2),this.diskNumberStart=a.readInt(2),this.internalFileAttributes=a.readInt(2),this.externalFileAttributes=a.readInt(4),this.localHeaderOffset=a.readInt(4),this.isEncrypted())throw new Error("Encrypted zip are not supported");a.skip(b),this.readExtraFields(a),this.parseZIP64ExtraField(a),this.fileComment=a.readData(this.fileCommentLength)},processAttributes:function(){this.unixPermissions=null,this.dosPermissions=null;var a=this.versionMadeBy>>8;this.dir=!!(16&this.externalFileAttributes),a===l&&(this.dosPermissions=63&this.externalFileAttributes),a===m&&(this.unixPermissions=this.externalFileAttributes>>16&65535),this.dir||"/"!==this.fileNameStr.slice(-1)||(this.dir=!0)},parseZIP64ExtraField:function(a){if(this.extraFields[1]){var b=e(this.extraFields[1].value);this.uncompressedSize===f.MAX_VALUE_32BITS&&(this.uncompressedSize=b.readInt(8)),this.compressedSize===f.MAX_VALUE_32BITS&&(this.compressedSize=b.readInt(8)),this.localHeaderOffset===f.MAX_VALUE_32BITS&&(this.localHeaderOffset=b.readInt(8)),this.diskNumberStart===f.MAX_VALUE_32BITS&&(this.diskNumberStart=b.readInt(4))}},readExtraFields:function(a){var b,c,d,e=a.index+this.extraFieldsLength;for(this.extraFields||(this.extraFields={});a.indexc;)b.push(arguments[c++]);return q[++p]=function(){h("function"==typeof a?a:Function(a),b)},d(p),p},n=function(a){delete q[a]},"process"==a("./_cof")(l)?d=function(a){l.nextTick(g(s,a,1))}:o?(e=new o,f=e.port2,e.port1.onmessage=t,d=g(f.postMessage,f,1)):k.addEventListener&&"function"==typeof postMessage&&!k.importScripts?(d=function(a){k.postMessage(a+"","*")},k.addEventListener("message",t,!1)):d=r in j("script")?function(a){i.appendChild(j("script"))[r]=function(){i.removeChild(this),s.call(a)}}:function(a){setTimeout(g(s,a,1),0)}),b.exports={set:m,clear:n}},{"./_cof":39,"./_ctx":41,"./_dom-create":43,"./_global":46,"./_html":48,"./_invoke":50}],55:[function(a,b,c){var d=a("./_is-object");b.exports=function(a,b){if(!d(a))return a;var c,e;if(b&&"function"==typeof(c=a.toString)&&!d(e=c.call(a)))return e;if("function"==typeof(c=a.valueOf)&&!d(e=c.call(a)))return e;if(!b&&"function"==typeof(c=a.toString)&&!d(e=c.call(a)))return e;throw TypeError("Can't convert object to primitive value")}},{"./_is-object":51}],56:[function(a,b,c){var d=a("./_export"),e=a("./_task");d(d.G+d.B,{setImmediate:e.set,clearImmediate:e.clear})},{"./_export":44,"./_task":54}],57:[function(a,b,c){(function(a){"use strict";function c(){k=!0;for(var a,b,c=l.length;c;){for(b=l,l=[],a=-1;++a0?b.windowBits=-b.windowBits:b.gzip&&b.windowBits>0&&b.windowBits<16&&(b.windowBits+=16),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new l,this.strm.avail_out=0;var c=h.deflateInit2(this.strm,b.level,b.method,b.windowBits,b.memLevel,b.strategy);if(c!==p)throw new Error(k[c]);if(b.header&&h.deflateSetHeader(this.strm,b.header),b.dictionary){var e;if(e="string"==typeof b.dictionary?j.string2buf(b.dictionary):"[object ArrayBuffer]"===m.call(b.dictionary)?new Uint8Array(b.dictionary):b.dictionary,c=h.deflateSetDictionary(this.strm,e),c!==p)throw new Error(k[c]);this._dict_set=!0}}function e(a,b){var c=new d(b);if(c.push(a,!0),c.err)throw c.msg;return c.result}function f(a,b){return b=b||{},b.raw=!0,e(a,b)}function g(a,b){return b=b||{},b.gzip=!0,e(a,b)}var h=a("./zlib/deflate"),i=a("./utils/common"),j=a("./utils/strings"),k=a("./zlib/messages"),l=a("./zlib/zstream"),m=Object.prototype.toString,n=0,o=4,p=0,q=1,r=2,s=-1,t=0,u=8;d.prototype.push=function(a,b){var c,d,e=this.strm,f=this.options.chunkSize;if(this.ended)return!1;d=b===~~b?b:b===!0?o:n,"string"==typeof a?e.input=j.string2buf(a):"[object ArrayBuffer]"===m.call(a)?e.input=new Uint8Array(a):e.input=a,e.next_in=0,e.avail_in=e.input.length;do{if(0===e.avail_out&&(e.output=new i.Buf8(f),e.next_out=0,e.avail_out=f),c=h.deflate(e,d),c!==q&&c!==p)return this.onEnd(c),this.ended=!0,!1;0!==e.avail_out&&(0!==e.avail_in||d!==o&&d!==r)||("string"===this.options.to?this.onData(j.buf2binstring(i.shrinkBuf(e.output,e.next_out))):this.onData(i.shrinkBuf(e.output,e.next_out)))}while((e.avail_in>0||0===e.avail_out)&&c!==q);return d===o?(c=h.deflateEnd(this.strm),this.onEnd(c),this.ended=!0,c===p):d!==r||(this.onEnd(p),e.avail_out=0,!0)},d.prototype.onData=function(a){this.chunks.push(a)},d.prototype.onEnd=function(a){a===p&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=i.flattenChunks(this.chunks)),this.chunks=[],this.err=a,this.msg=this.strm.msg},c.Deflate=d,c.deflate=e,c.deflateRaw=f,c.gzip=g},{"./utils/common":62,"./utils/strings":63,"./zlib/deflate":67,"./zlib/messages":72,"./zlib/zstream":74}],61:[function(a,b,c){"use strict";function d(a){if(!(this instanceof d))return new d(a);this.options=h.assign({chunkSize:16384,windowBits:0,to:""},a||{});var b=this.options;b.raw&&b.windowBits>=0&&b.windowBits<16&&(b.windowBits=-b.windowBits,0===b.windowBits&&(b.windowBits=-15)),!(b.windowBits>=0&&b.windowBits<16)||a&&a.windowBits||(b.windowBits+=32),b.windowBits>15&&b.windowBits<48&&0===(15&b.windowBits)&&(b.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new l,this.strm.avail_out=0;var c=g.inflateInit2(this.strm,b.windowBits);if(c!==j.Z_OK)throw new Error(k[c]);this.header=new m,g.inflateGetHeader(this.strm,this.header)}function e(a,b){var c=new d(b);if(c.push(a,!0),c.err)throw c.msg;return c.result}function f(a,b){return b=b||{},b.raw=!0,e(a,b)}var g=a("./zlib/inflate"),h=a("./utils/common"),i=a("./utils/strings"),j=a("./zlib/constants"),k=a("./zlib/messages"),l=a("./zlib/zstream"),m=a("./zlib/gzheader"),n=Object.prototype.toString;d.prototype.push=function(a,b){var c,d,e,f,k,l,m=this.strm,o=this.options.chunkSize,p=this.options.dictionary,q=!1;if(this.ended)return!1;d=b===~~b?b:b===!0?j.Z_FINISH:j.Z_NO_FLUSH,"string"==typeof a?m.input=i.binstring2buf(a):"[object ArrayBuffer]"===n.call(a)?m.input=new Uint8Array(a):m.input=a,m.next_in=0,m.avail_in=m.input.length;do{if(0===m.avail_out&&(m.output=new h.Buf8(o),m.next_out=0,m.avail_out=o),c=g.inflate(m,j.Z_NO_FLUSH),c===j.Z_NEED_DICT&&p&&(l="string"==typeof p?i.string2buf(p):"[object ArrayBuffer]"===n.call(p)?new Uint8Array(p):p,c=g.inflateSetDictionary(this.strm,l)),c===j.Z_BUF_ERROR&&q===!0&&(c=j.Z_OK,q=!1),c!==j.Z_STREAM_END&&c!==j.Z_OK)return this.onEnd(c),this.ended=!0,!1;m.next_out&&(0!==m.avail_out&&c!==j.Z_STREAM_END&&(0!==m.avail_in||d!==j.Z_FINISH&&d!==j.Z_SYNC_FLUSH)||("string"===this.options.to?(e=i.utf8border(m.output,m.next_out),f=m.next_out-e,k=i.buf2string(m.output,e),m.next_out=f,m.avail_out=o-f,f&&h.arraySet(m.output,m.output,e,f,0),this.onData(k)):this.onData(h.shrinkBuf(m.output,m.next_out)))),0===m.avail_in&&0===m.avail_out&&(q=!0)}while((m.avail_in>0||0===m.avail_out)&&c!==j.Z_STREAM_END);return c===j.Z_STREAM_END&&(d=j.Z_FINISH),d===j.Z_FINISH?(c=g.inflateEnd(this.strm),this.onEnd(c),this.ended=!0,c===j.Z_OK):d!==j.Z_SYNC_FLUSH||(this.onEnd(j.Z_OK),m.avail_out=0,!0)},d.prototype.onData=function(a){this.chunks.push(a)},d.prototype.onEnd=function(a){a===j.Z_OK&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=h.flattenChunks(this.chunks)),this.chunks=[],this.err=a,this.msg=this.strm.msg},c.Inflate=d,c.inflate=e,c.inflateRaw=f,c.ungzip=e},{"./utils/common":62,"./utils/strings":63,"./zlib/constants":65,"./zlib/gzheader":68,"./zlib/inflate":70,"./zlib/messages":72,"./zlib/zstream":74}],62:[function(a,b,c){"use strict";var d="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Int32Array;c.assign=function(a){for(var b=Array.prototype.slice.call(arguments,1);b.length;){var c=b.shift();if(c){if("object"!=typeof c)throw new TypeError(c+"must be non-object");for(var d in c)c.hasOwnProperty(d)&&(a[d]=c[d])}}return a},c.shrinkBuf=function(a,b){return a.length===b?a:a.subarray?a.subarray(0,b):(a.length=b,a)};var e={arraySet:function(a,b,c,d,e){if(b.subarray&&a.subarray)return void a.set(b.subarray(c,c+d),e);for(var f=0;f=252?6:j>=248?5:j>=240?4:j>=224?3:j>=192?2:1;i[254]=i[254]=1,c.string2buf=function(a){var b,c,d,f,g,h=a.length,i=0;for(f=0;f>>6,b[g++]=128|63&c):c<65536?(b[g++]=224|c>>>12,b[g++]=128|c>>>6&63,b[g++]=128|63&c):(b[g++]=240|c>>>18,b[g++]=128|c>>>12&63,b[g++]=128|c>>>6&63,b[g++]=128|63&c);return b},c.buf2binstring=function(a){return d(a,a.length)},c.binstring2buf=function(a){for(var b=new e.Buf8(a.length),c=0,d=b.length;c4)j[e++]=65533,c+=g-1;else{for(f&=2===g?31:3===g?15:7;g>1&&c1?j[e++]=65533:f<65536?j[e++]=f:(f-=65536,j[e++]=55296|f>>10&1023,j[e++]=56320|1023&f)}return d(j,e)},c.utf8border=function(a,b){var c;for(b=b||a.length,b>a.length&&(b=a.length),c=b-1;c>=0&&128===(192&a[c]);)c--;return c<0?b:0===c?b:c+i[a[c]]>b?c:b}},{"./common":62}],64:[function(a,b,c){"use strict";function d(a,b,c,d){for(var e=65535&a|0,f=a>>>16&65535|0,g=0;0!==c;){g=c>2e3?2e3:c,c-=g;do e=e+b[d++]|0,f=f+e|0;while(--g);e%=65521,f%=65521}return e|f<<16|0}b.exports=d},{}],65:[function(a,b,c){"use strict";b.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}},{}],66:[function(a,b,c){"use strict";function d(){ -for(var a,b=[],c=0;c<256;c++){a=c;for(var d=0;d<8;d++)a=1&a?3988292384^a>>>1:a>>>1;b[c]=a}return b}function e(a,b,c,d){var e=f,g=d+c;a^=-1;for(var h=d;h>>8^e[255&(a^b[h])];return a^-1}var f=d();b.exports=e},{}],67:[function(a,b,c){"use strict";function d(a,b){return a.msg=I[b],b}function e(a){return(a<<1)-(a>4?9:0)}function f(a){for(var b=a.length;--b>=0;)a[b]=0}function g(a){var b=a.state,c=b.pending;c>a.avail_out&&(c=a.avail_out),0!==c&&(E.arraySet(a.output,b.pending_buf,b.pending_out,c,a.next_out),a.next_out+=c,b.pending_out+=c,a.total_out+=c,a.avail_out-=c,b.pending-=c,0===b.pending&&(b.pending_out=0))}function h(a,b){F._tr_flush_block(a,a.block_start>=0?a.block_start:-1,a.strstart-a.block_start,b),a.block_start=a.strstart,g(a.strm)}function i(a,b){a.pending_buf[a.pending++]=b}function j(a,b){a.pending_buf[a.pending++]=b>>>8&255,a.pending_buf[a.pending++]=255&b}function k(a,b,c,d){var e=a.avail_in;return e>d&&(e=d),0===e?0:(a.avail_in-=e,E.arraySet(b,a.input,a.next_in,e,c),1===a.state.wrap?a.adler=G(a.adler,b,e,c):2===a.state.wrap&&(a.adler=H(a.adler,b,e,c)),a.next_in+=e,a.total_in+=e,e)}function l(a,b){var c,d,e=a.max_chain_length,f=a.strstart,g=a.prev_length,h=a.nice_match,i=a.strstart>a.w_size-la?a.strstart-(a.w_size-la):0,j=a.window,k=a.w_mask,l=a.prev,m=a.strstart+ka,n=j[f+g-1],o=j[f+g];a.prev_length>=a.good_match&&(e>>=2),h>a.lookahead&&(h=a.lookahead);do if(c=b,j[c+g]===o&&j[c+g-1]===n&&j[c]===j[f]&&j[++c]===j[f+1]){f+=2,c++;do;while(j[++f]===j[++c]&&j[++f]===j[++c]&&j[++f]===j[++c]&&j[++f]===j[++c]&&j[++f]===j[++c]&&j[++f]===j[++c]&&j[++f]===j[++c]&&j[++f]===j[++c]&&fg){if(a.match_start=b,g=d,d>=h)break;n=j[f+g-1],o=j[f+g]}}while((b=l[b&k])>i&&0!==--e);return g<=a.lookahead?g:a.lookahead}function m(a){var b,c,d,e,f,g=a.w_size;do{if(e=a.window_size-a.lookahead-a.strstart,a.strstart>=g+(g-la)){E.arraySet(a.window,a.window,g,g,0),a.match_start-=g,a.strstart-=g,a.block_start-=g,c=a.hash_size,b=c;do d=a.head[--b],a.head[b]=d>=g?d-g:0;while(--c);c=g,b=c;do d=a.prev[--b],a.prev[b]=d>=g?d-g:0;while(--c);e+=g}if(0===a.strm.avail_in)break;if(c=k(a.strm,a.window,a.strstart+a.lookahead,e),a.lookahead+=c,a.lookahead+a.insert>=ja)for(f=a.strstart-a.insert,a.ins_h=a.window[f],a.ins_h=(a.ins_h<a.pending_buf_size-5&&(c=a.pending_buf_size-5);;){if(a.lookahead<=1){if(m(a),0===a.lookahead&&b===J)return ua;if(0===a.lookahead)break}a.strstart+=a.lookahead,a.lookahead=0;var d=a.block_start+c;if((0===a.strstart||a.strstart>=d)&&(a.lookahead=a.strstart-d,a.strstart=d,h(a,!1),0===a.strm.avail_out))return ua;if(a.strstart-a.block_start>=a.w_size-la&&(h(a,!1),0===a.strm.avail_out))return ua}return a.insert=0,b===M?(h(a,!0),0===a.strm.avail_out?wa:xa):a.strstart>a.block_start&&(h(a,!1),0===a.strm.avail_out)?ua:ua}function o(a,b){for(var c,d;;){if(a.lookahead=ja&&(a.ins_h=(a.ins_h<=ja)if(d=F._tr_tally(a,a.strstart-a.match_start,a.match_length-ja),a.lookahead-=a.match_length,a.match_length<=a.max_lazy_match&&a.lookahead>=ja){a.match_length--;do a.strstart++,a.ins_h=(a.ins_h<=ja&&(a.ins_h=(a.ins_h<4096)&&(a.match_length=ja-1)),a.prev_length>=ja&&a.match_length<=a.prev_length){e=a.strstart+a.lookahead-ja,d=F._tr_tally(a,a.strstart-1-a.prev_match,a.prev_length-ja),a.lookahead-=a.prev_length-1,a.prev_length-=2;do++a.strstart<=e&&(a.ins_h=(a.ins_h<=ja&&a.strstart>0&&(e=a.strstart-1,d=g[e],d===g[++e]&&d===g[++e]&&d===g[++e])){f=a.strstart+ka;do;while(d===g[++e]&&d===g[++e]&&d===g[++e]&&d===g[++e]&&d===g[++e]&&d===g[++e]&&d===g[++e]&&d===g[++e]&&ea.lookahead&&(a.match_length=a.lookahead)}if(a.match_length>=ja?(c=F._tr_tally(a,1,a.match_length-ja),a.lookahead-=a.match_length,a.strstart+=a.match_length,a.match_length=0):(c=F._tr_tally(a,0,a.window[a.strstart]),a.lookahead--,a.strstart++),c&&(h(a,!1),0===a.strm.avail_out))return ua}return a.insert=0,b===M?(h(a,!0),0===a.strm.avail_out?wa:xa):a.last_lit&&(h(a,!1),0===a.strm.avail_out)?ua:va}function r(a,b){for(var c;;){if(0===a.lookahead&&(m(a),0===a.lookahead)){if(b===J)return ua;break}if(a.match_length=0,c=F._tr_tally(a,0,a.window[a.strstart]),a.lookahead--,a.strstart++,c&&(h(a,!1),0===a.strm.avail_out))return ua}return a.insert=0,b===M?(h(a,!0),0===a.strm.avail_out?wa:xa):a.last_lit&&(h(a,!1),0===a.strm.avail_out)?ua:va}function s(a,b,c,d,e){this.good_length=a,this.max_lazy=b,this.nice_length=c,this.max_chain=d,this.func=e}function t(a){a.window_size=2*a.w_size,f(a.head),a.max_lazy_match=D[a.level].max_lazy,a.good_match=D[a.level].good_length,a.nice_match=D[a.level].nice_length,a.max_chain_length=D[a.level].max_chain,a.strstart=0,a.block_start=0,a.lookahead=0,a.insert=0,a.match_length=a.prev_length=ja-1,a.match_available=0,a.ins_h=0}function u(){this.strm=null,this.status=0,this.pending_buf=null,this.pending_buf_size=0,this.pending_out=0,this.pending=0,this.wrap=0,this.gzhead=null,this.gzindex=0,this.method=$,this.last_flush=-1,this.w_size=0,this.w_bits=0,this.w_mask=0,this.window=null,this.window_size=0,this.prev=null,this.head=null,this.ins_h=0,this.hash_size=0,this.hash_bits=0,this.hash_mask=0,this.hash_shift=0,this.block_start=0,this.match_length=0,this.prev_match=0,this.match_available=0,this.strstart=0,this.match_start=0,this.lookahead=0,this.prev_length=0,this.max_chain_length=0,this.max_lazy_match=0,this.level=0,this.strategy=0,this.good_match=0,this.nice_match=0,this.dyn_ltree=new E.Buf16(2*ha),this.dyn_dtree=new E.Buf16(2*(2*fa+1)),this.bl_tree=new E.Buf16(2*(2*ga+1)),f(this.dyn_ltree),f(this.dyn_dtree),f(this.bl_tree),this.l_desc=null,this.d_desc=null,this.bl_desc=null,this.bl_count=new E.Buf16(ia+1),this.heap=new E.Buf16(2*ea+1),f(this.heap),this.heap_len=0,this.heap_max=0,this.depth=new E.Buf16(2*ea+1),f(this.depth),this.l_buf=0,this.lit_bufsize=0,this.last_lit=0,this.d_buf=0,this.opt_len=0,this.static_len=0,this.matches=0,this.insert=0,this.bi_buf=0,this.bi_valid=0}function v(a){var b;return a&&a.state?(a.total_in=a.total_out=0,a.data_type=Z,b=a.state,b.pending=0,b.pending_out=0,b.wrap<0&&(b.wrap=-b.wrap),b.status=b.wrap?na:sa,a.adler=2===b.wrap?0:1,b.last_flush=J,F._tr_init(b),O):d(a,Q)}function w(a){var b=v(a);return b===O&&t(a.state),b}function x(a,b){return a&&a.state?2!==a.state.wrap?Q:(a.state.gzhead=b,O):Q}function y(a,b,c,e,f,g){if(!a)return Q;var h=1;if(b===T&&(b=6),e<0?(h=0,e=-e):e>15&&(h=2,e-=16),f<1||f>_||c!==$||e<8||e>15||b<0||b>9||g<0||g>X)return d(a,Q);8===e&&(e=9);var i=new u;return a.state=i,i.strm=a,i.wrap=h,i.gzhead=null,i.w_bits=e,i.w_size=1<N||b<0)return a?d(a,Q):Q;if(h=a.state,!a.output||!a.input&&0!==a.avail_in||h.status===ta&&b!==M)return d(a,0===a.avail_out?S:Q);if(h.strm=a,c=h.last_flush,h.last_flush=b,h.status===na)if(2===h.wrap)a.adler=0,i(h,31),i(h,139),i(h,8),h.gzhead?(i(h,(h.gzhead.text?1:0)+(h.gzhead.hcrc?2:0)+(h.gzhead.extra?4:0)+(h.gzhead.name?8:0)+(h.gzhead.comment?16:0)),i(h,255&h.gzhead.time),i(h,h.gzhead.time>>8&255),i(h,h.gzhead.time>>16&255),i(h,h.gzhead.time>>24&255),i(h,9===h.level?2:h.strategy>=V||h.level<2?4:0),i(h,255&h.gzhead.os),h.gzhead.extra&&h.gzhead.extra.length&&(i(h,255&h.gzhead.extra.length),i(h,h.gzhead.extra.length>>8&255)),h.gzhead.hcrc&&(a.adler=H(a.adler,h.pending_buf,h.pending,0)),h.gzindex=0,h.status=oa):(i(h,0),i(h,0),i(h,0),i(h,0),i(h,0),i(h,9===h.level?2:h.strategy>=V||h.level<2?4:0),i(h,ya),h.status=sa);else{var m=$+(h.w_bits-8<<4)<<8,n=-1;n=h.strategy>=V||h.level<2?0:h.level<6?1:6===h.level?2:3,m|=n<<6,0!==h.strstart&&(m|=ma),m+=31-m%31,h.status=sa,j(h,m),0!==h.strstart&&(j(h,a.adler>>>16),j(h,65535&a.adler)),a.adler=1}if(h.status===oa)if(h.gzhead.extra){for(k=h.pending;h.gzindex<(65535&h.gzhead.extra.length)&&(h.pending!==h.pending_buf_size||(h.gzhead.hcrc&&h.pending>k&&(a.adler=H(a.adler,h.pending_buf,h.pending-k,k)),g(a),k=h.pending,h.pending!==h.pending_buf_size));)i(h,255&h.gzhead.extra[h.gzindex]),h.gzindex++;h.gzhead.hcrc&&h.pending>k&&(a.adler=H(a.adler,h.pending_buf,h.pending-k,k)),h.gzindex===h.gzhead.extra.length&&(h.gzindex=0,h.status=pa)}else h.status=pa;if(h.status===pa)if(h.gzhead.name){k=h.pending;do{if(h.pending===h.pending_buf_size&&(h.gzhead.hcrc&&h.pending>k&&(a.adler=H(a.adler,h.pending_buf,h.pending-k,k)),g(a),k=h.pending,h.pending===h.pending_buf_size)){l=1;break}l=h.gzindexk&&(a.adler=H(a.adler,h.pending_buf,h.pending-k,k)),0===l&&(h.gzindex=0,h.status=qa)}else h.status=qa;if(h.status===qa)if(h.gzhead.comment){k=h.pending;do{if(h.pending===h.pending_buf_size&&(h.gzhead.hcrc&&h.pending>k&&(a.adler=H(a.adler,h.pending_buf,h.pending-k,k)),g(a),k=h.pending,h.pending===h.pending_buf_size)){l=1;break}l=h.gzindexk&&(a.adler=H(a.adler,h.pending_buf,h.pending-k,k)),0===l&&(h.status=ra)}else h.status=ra;if(h.status===ra&&(h.gzhead.hcrc?(h.pending+2>h.pending_buf_size&&g(a),h.pending+2<=h.pending_buf_size&&(i(h,255&a.adler),i(h,a.adler>>8&255),a.adler=0,h.status=sa)):h.status=sa),0!==h.pending){if(g(a),0===a.avail_out)return h.last_flush=-1,O}else if(0===a.avail_in&&e(b)<=e(c)&&b!==M)return d(a,S);if(h.status===ta&&0!==a.avail_in)return d(a,S);if(0!==a.avail_in||0!==h.lookahead||b!==J&&h.status!==ta){var o=h.strategy===V?r(h,b):h.strategy===W?q(h,b):D[h.level].func(h,b);if(o!==wa&&o!==xa||(h.status=ta),o===ua||o===wa)return 0===a.avail_out&&(h.last_flush=-1),O;if(o===va&&(b===K?F._tr_align(h):b!==N&&(F._tr_stored_block(h,0,0,!1),b===L&&(f(h.head),0===h.lookahead&&(h.strstart=0,h.block_start=0,h.insert=0))),g(a),0===a.avail_out))return h.last_flush=-1,O}return b!==M?O:h.wrap<=0?P:(2===h.wrap?(i(h,255&a.adler),i(h,a.adler>>8&255),i(h,a.adler>>16&255),i(h,a.adler>>24&255),i(h,255&a.total_in),i(h,a.total_in>>8&255),i(h,a.total_in>>16&255),i(h,a.total_in>>24&255)):(j(h,a.adler>>>16),j(h,65535&a.adler)),g(a),h.wrap>0&&(h.wrap=-h.wrap),0!==h.pending?O:P)}function B(a){var b;return a&&a.state?(b=a.state.status,b!==na&&b!==oa&&b!==pa&&b!==qa&&b!==ra&&b!==sa&&b!==ta?d(a,Q):(a.state=null,b===sa?d(a,R):O)):Q}function C(a,b){var c,d,e,g,h,i,j,k,l=b.length;if(!a||!a.state)return Q;if(c=a.state,g=c.wrap,2===g||1===g&&c.status!==na||c.lookahead)return Q;for(1===g&&(a.adler=G(a.adler,b,l,0)),c.wrap=0,l>=c.w_size&&(0===g&&(f(c.head),c.strstart=0,c.block_start=0,c.insert=0),k=new E.Buf8(c.w_size),E.arraySet(k,b,l-c.w_size,c.w_size,0),b=k,l=c.w_size),h=a.avail_in,i=a.next_in,j=a.input,a.avail_in=l,a.next_in=0,a.input=b,m(c);c.lookahead>=ja;){d=c.strstart,e=c.lookahead-(ja-1);do c.ins_h=(c.ins_h<>>24,p>>>=w,q-=w,w=v>>>16&255,0===w)C[h++]=65535&v;else{if(!(16&w)){if(0===(64&w)){v=r[(65535&v)+(p&(1<>>=w,q-=w),q<15&&(p+=B[f++]<>>24,p>>>=w,q-=w,w=v>>>16&255,!(16&w)){if(0===(64&w)){v=s[(65535&v)+(p&(1<k){a.msg="invalid distance too far back",c.mode=d;break a}if(p>>>=w,q-=w,w=h-i,y>w){if(w=y-w,w>m&&c.sane){a.msg="invalid distance too far back",c.mode=d;break a}if(z=0,A=o,0===n){if(z+=l-w,w2;)C[h++]=A[z++],C[h++]=A[z++],C[h++]=A[z++],x-=3;x&&(C[h++]=A[z++],x>1&&(C[h++]=A[z++]))}else{z=h-y;do C[h++]=C[z++],C[h++]=C[z++],C[h++]=C[z++],x-=3;while(x>2);x&&(C[h++]=C[z++],x>1&&(C[h++]=C[z++]))}break}}break}}while(f>3,f-=x,q-=x<<3,p&=(1<>>24&255)+(a>>>8&65280)+((65280&a)<<8)+((255&a)<<24)}function e(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new s.Buf16(320),this.work=new s.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function f(a){var b;return a&&a.state?(b=a.state,a.total_in=a.total_out=b.total=0,a.msg="",b.wrap&&(a.adler=1&b.wrap),b.mode=L,b.last=0,b.havedict=0,b.dmax=32768,b.head=null,b.hold=0,b.bits=0,b.lencode=b.lendyn=new s.Buf32(pa),b.distcode=b.distdyn=new s.Buf32(qa),b.sane=1,b.back=-1,D):G}function g(a){var b;return a&&a.state?(b=a.state,b.wsize=0,b.whave=0,b.wnext=0,f(a)):G}function h(a,b){var c,d;return a&&a.state?(d=a.state,b<0?(c=0,b=-b):(c=(b>>4)+1,b<48&&(b&=15)),b&&(b<8||b>15)?G:(null!==d.window&&d.wbits!==b&&(d.window=null),d.wrap=c,d.wbits=b,g(a))):G}function i(a,b){var c,d;return a?(d=new e,a.state=d,d.window=null,c=h(a,b),c!==D&&(a.state=null),c):G}function j(a){return i(a,sa)}function k(a){if(ta){var b;for(q=new s.Buf32(512),r=new s.Buf32(32),b=0;b<144;)a.lens[b++]=8;for(;b<256;)a.lens[b++]=9;for(;b<280;)a.lens[b++]=7;for(;b<288;)a.lens[b++]=8;for(w(y,a.lens,0,288,q,0,a.work,{bits:9}),b=0;b<32;)a.lens[b++]=5;w(z,a.lens,0,32,r,0,a.work,{bits:5}),ta=!1}a.lencode=q,a.lenbits=9,a.distcode=r,a.distbits=5}function l(a,b,c,d){var e,f=a.state;return null===f.window&&(f.wsize=1<=f.wsize?(s.arraySet(f.window,b,c-f.wsize,f.wsize,0),f.wnext=0,f.whave=f.wsize):(e=f.wsize-f.wnext,e>d&&(e=d),s.arraySet(f.window,b,c-d,e,f.wnext),d-=e,d?(s.arraySet(f.window,b,c-d,d,0),f.wnext=d,f.whave=f.wsize):(f.wnext+=e,f.wnext===f.wsize&&(f.wnext=0),f.whave>>8&255,c.check=u(c.check,Ba,2,0),m=0,n=0,c.mode=M;break}if(c.flags=0,c.head&&(c.head.done=!1),!(1&c.wrap)||(((255&m)<<8)+(m>>8))%31){a.msg="incorrect header check",c.mode=ma;break}if((15&m)!==K){a.msg="unknown compression method",c.mode=ma;break}if(m>>>=4,n-=4,wa=(15&m)+8,0===c.wbits)c.wbits=wa;else if(wa>c.wbits){a.msg="invalid window size",c.mode=ma;break}c.dmax=1<>8&1),512&c.flags&&(Ba[0]=255&m,Ba[1]=m>>>8&255,c.check=u(c.check,Ba,2,0)),m=0,n=0,c.mode=N;case N:for(;n<32;){if(0===i)break a;i--,m+=e[g++]<>>8&255,Ba[2]=m>>>16&255,Ba[3]=m>>>24&255,c.check=u(c.check,Ba,4,0)),m=0,n=0,c.mode=O;case O:for(;n<16;){if(0===i)break a;i--,m+=e[g++]<>8),512&c.flags&&(Ba[0]=255&m,Ba[1]=m>>>8&255,c.check=u(c.check,Ba,2,0)),m=0,n=0,c.mode=P;case P:if(1024&c.flags){for(;n<16;){if(0===i)break a;i--,m+=e[g++]<>>8&255,c.check=u(c.check,Ba,2,0)),m=0,n=0}else c.head&&(c.head.extra=null);c.mode=Q;case Q:if(1024&c.flags&&(q=c.length,q>i&&(q=i),q&&(c.head&&(wa=c.head.extra_len-c.length,c.head.extra||(c.head.extra=new Array(c.head.extra_len)),s.arraySet(c.head.extra,e,g,q,wa)),512&c.flags&&(c.check=u(c.check,e,q,g)),i-=q,g+=q,c.length-=q),c.length))break a;c.length=0,c.mode=R;case R:if(2048&c.flags){if(0===i)break a;q=0;do wa=e[g+q++],c.head&&wa&&c.length<65536&&(c.head.name+=String.fromCharCode(wa));while(wa&&q>9&1,c.head.done=!0),a.adler=c.check=0,c.mode=W;break;case U:for(;n<32;){if(0===i)break a;i--,m+=e[g++]<>>=7&n,n-=7&n,c.mode=ja;break}for(;n<3;){if(0===i)break a;i--,m+=e[g++]<>>=1,n-=1,3&m){case 0:c.mode=Y;break;case 1:if(k(c),c.mode=ca,b===C){m>>>=2,n-=2;break a}break;case 2:c.mode=_;break;case 3:a.msg="invalid block type",c.mode=ma}m>>>=2,n-=2;break;case Y:for(m>>>=7&n,n-=7&n;n<32;){if(0===i)break a;i--,m+=e[g++]<>>16^65535)){a.msg="invalid stored block lengths",c.mode=ma;break}if(c.length=65535&m,m=0,n=0,c.mode=Z,b===C)break a;case Z:c.mode=$;case $:if(q=c.length){if(q>i&&(q=i),q>j&&(q=j),0===q)break a;s.arraySet(f,e,g,q,h),i-=q,g+=q,j-=q,h+=q,c.length-=q;break}c.mode=W;break;case _:for(;n<14;){if(0===i)break a;i--,m+=e[g++]<>>=5,n-=5,c.ndist=(31&m)+1,m>>>=5,n-=5,c.ncode=(15&m)+4,m>>>=4,n-=4,c.nlen>286||c.ndist>30){a.msg="too many length or distance symbols",c.mode=ma;break}c.have=0,c.mode=aa;case aa:for(;c.have>>=3,n-=3}for(;c.have<19;)c.lens[Ca[c.have++]]=0;if(c.lencode=c.lendyn,c.lenbits=7,ya={bits:c.lenbits},xa=w(x,c.lens,0,19,c.lencode,0,c.work,ya),c.lenbits=ya.bits,xa){a.msg="invalid code lengths set",c.mode=ma;break}c.have=0,c.mode=ba;case ba:for(;c.have>>24,ra=Aa>>>16&255,sa=65535&Aa,!(qa<=n);){if(0===i)break a;i--,m+=e[g++]<>>=qa,n-=qa,c.lens[c.have++]=sa;else{if(16===sa){for(za=qa+2;n>>=qa,n-=qa,0===c.have){a.msg="invalid bit length repeat",c.mode=ma;break}wa=c.lens[c.have-1],q=3+(3&m),m>>>=2,n-=2}else if(17===sa){for(za=qa+3;n>>=qa,n-=qa,wa=0,q=3+(7&m),m>>>=3,n-=3}else{for(za=qa+7;n>>=qa,n-=qa,wa=0,q=11+(127&m),m>>>=7,n-=7}if(c.have+q>c.nlen+c.ndist){a.msg="invalid bit length repeat",c.mode=ma;break}for(;q--;)c.lens[c.have++]=wa}}if(c.mode===ma)break;if(0===c.lens[256]){a.msg="invalid code -- missing end-of-block",c.mode=ma;break}if(c.lenbits=9,ya={bits:c.lenbits},xa=w(y,c.lens,0,c.nlen,c.lencode,0,c.work,ya),c.lenbits=ya.bits,xa){a.msg="invalid literal/lengths set",c.mode=ma;break}if(c.distbits=6,c.distcode=c.distdyn,ya={bits:c.distbits},xa=w(z,c.lens,c.nlen,c.ndist,c.distcode,0,c.work,ya),c.distbits=ya.bits,xa){a.msg="invalid distances set",c.mode=ma;break}if(c.mode=ca,b===C)break a;case ca:c.mode=da;case da:if(i>=6&&j>=258){a.next_out=h,a.avail_out=j,a.next_in=g,a.avail_in=i,c.hold=m,c.bits=n,v(a,p),h=a.next_out,f=a.output,j=a.avail_out,g=a.next_in,e=a.input,i=a.avail_in,m=c.hold,n=c.bits,c.mode===W&&(c.back=-1);break}for(c.back=0;Aa=c.lencode[m&(1<>>24,ra=Aa>>>16&255,sa=65535&Aa,!(qa<=n);){if(0===i)break a;i--,m+=e[g++]<>ta)],qa=Aa>>>24,ra=Aa>>>16&255,sa=65535&Aa,!(ta+qa<=n);){if(0===i)break a;i--,m+=e[g++]<>>=ta,n-=ta,c.back+=ta}if(m>>>=qa,n-=qa,c.back+=qa,c.length=sa,0===ra){c.mode=ia;break}if(32&ra){c.back=-1,c.mode=W;break}if(64&ra){a.msg="invalid literal/length code",c.mode=ma;break}c.extra=15&ra,c.mode=ea;case ea:if(c.extra){for(za=c.extra;n>>=c.extra,n-=c.extra,c.back+=c.extra}c.was=c.length,c.mode=fa;case fa:for(;Aa=c.distcode[m&(1<>>24,ra=Aa>>>16&255,sa=65535&Aa,!(qa<=n);){if(0===i)break a;i--,m+=e[g++]<>ta)],qa=Aa>>>24,ra=Aa>>>16&255,sa=65535&Aa,!(ta+qa<=n);){if(0===i)break a;i--,m+=e[g++]<>>=ta,n-=ta,c.back+=ta}if(m>>>=qa,n-=qa,c.back+=qa,64&ra){a.msg="invalid distance code",c.mode=ma;break}c.offset=sa,c.extra=15&ra,c.mode=ga;case ga:if(c.extra){for(za=c.extra;n>>=c.extra,n-=c.extra,c.back+=c.extra}if(c.offset>c.dmax){a.msg="invalid distance too far back",c.mode=ma;break}c.mode=ha;case ha:if(0===j)break a;if(q=p-j,c.offset>q){if(q=c.offset-q,q>c.whave&&c.sane){a.msg="invalid distance too far back",c.mode=ma;break}q>c.wnext?(q-=c.wnext,r=c.wsize-q):r=c.wnext-q,q>c.length&&(q=c.length),pa=c.window}else pa=f,r=h-c.offset,q=c.length;q>j&&(q=j),j-=q,c.length-=q;do f[h++]=pa[r++];while(--q);0===c.length&&(c.mode=da);break;case ia:if(0===j)break a;f[h++]=c.length,j--,c.mode=da;break;case ja:if(c.wrap){for(;n<32;){if(0===i)break a;i--,m|=e[g++]<=1&&0===P[G];G--);if(H>G&&(H=G),0===G)return p[q++]=20971520,p[q++]=20971520,s.bits=1,0;for(F=1;F0&&(a===h||1!==G))return-1;for(Q[1]=0,D=1;Df||a===j&&L>g)return 1;for(var T=0;;){T++,z=D-J,r[E]y?(A=R[S+r[E]],B=N[O+r[E]]):(A=96,B=0),t=1<>J)+u]=z<<24|A<<16|B|0;while(0!==u);for(t=1<>=1;if(0!==t?(M&=t-1,M+=t):M=0,E++,0===--P[D]){if(D===G)break;D=b[c+r[E]]}if(D>H&&(M&w)!==v){for(0===J&&(J=H),x+=F,I=D-J,K=1<f||a===j&&L>g)return 1;v=M&w,p[v]=H<<24|I<<16|x-q|0}}return 0!==M&&(p[x+M]=D-J<<24|64<<16|0),s.bits=H,0}},{"../utils/common":62}],72:[function(a,b,c){"use strict";b.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],73:[function(a,b,c){"use strict";function d(a){for(var b=a.length;--b>=0;)a[b]=0}function e(a,b,c,d,e){this.static_tree=a,this.extra_bits=b,this.extra_base=c,this.elems=d,this.max_length=e,this.has_stree=a&&a.length}function f(a,b){this.dyn_tree=a,this.max_code=0,this.stat_desc=b}function g(a){return a<256?ia[a]:ia[256+(a>>>7)]}function h(a,b){a.pending_buf[a.pending++]=255&b,a.pending_buf[a.pending++]=b>>>8&255}function i(a,b,c){a.bi_valid>X-c?(a.bi_buf|=b<>X-a.bi_valid,a.bi_valid+=c-X):(a.bi_buf|=b<>>=1,c<<=1;while(--b>0);return c>>>1}function l(a){16===a.bi_valid?(h(a,a.bi_buf),a.bi_buf=0,a.bi_valid=0):a.bi_valid>=8&&(a.pending_buf[a.pending++]=255&a.bi_buf,a.bi_buf>>=8,a.bi_valid-=8)}function m(a,b){var c,d,e,f,g,h,i=b.dyn_tree,j=b.max_code,k=b.stat_desc.static_tree,l=b.stat_desc.has_stree,m=b.stat_desc.extra_bits,n=b.stat_desc.extra_base,o=b.stat_desc.max_length,p=0;for(f=0;f<=W;f++)a.bl_count[f]=0;for(i[2*a.heap[a.heap_max]+1]=0,c=a.heap_max+1;co&&(f=o,p++),i[2*d+1]=f,d>j||(a.bl_count[f]++,g=0,d>=n&&(g=m[d-n]),h=i[2*d],a.opt_len+=h*(f+g),l&&(a.static_len+=h*(k[2*d+1]+g)));if(0!==p){do{for(f=o-1;0===a.bl_count[f];)f--;a.bl_count[f]--,a.bl_count[f+1]+=2,a.bl_count[o]--,p-=2}while(p>0);for(f=o;0!==f;f--)for(d=a.bl_count[f];0!==d;)e=a.heap[--c],e>j||(i[2*e+1]!==f&&(a.opt_len+=(f-i[2*e+1])*i[2*e],i[2*e+1]=f),d--)}}function n(a,b,c){var d,e,f=new Array(W+1),g=0; -for(d=1;d<=W;d++)f[d]=g=g+c[d-1]<<1;for(e=0;e<=b;e++){var h=a[2*e+1];0!==h&&(a[2*e]=k(f[h]++,h))}}function o(){var a,b,c,d,f,g=new Array(W+1);for(c=0,d=0;d>=7;d8?h(a,a.bi_buf):a.bi_valid>0&&(a.pending_buf[a.pending++]=a.bi_buf),a.bi_buf=0,a.bi_valid=0}function r(a,b,c,d){q(a),d&&(h(a,c),h(a,~c)),G.arraySet(a.pending_buf,a.window,b,c,a.pending),a.pending+=c}function s(a,b,c,d){var e=2*b,f=2*c;return a[e]>1;c>=1;c--)t(a,f,c);e=i;do c=a.heap[1],a.heap[1]=a.heap[a.heap_len--],t(a,f,1),d=a.heap[1],a.heap[--a.heap_max]=c,a.heap[--a.heap_max]=d,f[2*e]=f[2*c]+f[2*d],a.depth[e]=(a.depth[c]>=a.depth[d]?a.depth[c]:a.depth[d])+1,f[2*c+1]=f[2*d+1]=e,a.heap[1]=e++,t(a,f,1);while(a.heap_len>=2);a.heap[--a.heap_max]=a.heap[1],m(a,b),n(f,j,a.bl_count)}function w(a,b,c){var d,e,f=-1,g=b[1],h=0,i=7,j=4;for(0===g&&(i=138,j=3),b[2*(c+1)+1]=65535,d=0;d<=c;d++)e=g,g=b[2*(d+1)+1],++h=3&&0===a.bl_tree[2*ea[b]+1];b--);return a.opt_len+=3*(b+1)+5+5+4,b}function z(a,b,c,d){var e;for(i(a,b-257,5),i(a,c-1,5),i(a,d-4,4),e=0;e>>=1)if(1&c&&0!==a.dyn_ltree[2*b])return I;if(0!==a.dyn_ltree[18]||0!==a.dyn_ltree[20]||0!==a.dyn_ltree[26])return J;for(b=32;b0?(a.strm.data_type===K&&(a.strm.data_type=A(a)),v(a,a.l_desc),v(a,a.d_desc),g=y(a),e=a.opt_len+3+7>>>3,f=a.static_len+3+7>>>3,f<=e&&(e=f)):e=f=c+5,c+4<=e&&b!==-1?C(a,b,c,d):a.strategy===H||f===e?(i(a,(M<<1)+(d?1:0),3),u(a,ga,ha)):(i(a,(N<<1)+(d?1:0),3),z(a,a.l_desc.max_code+1,a.d_desc.max_code+1,g+1),u(a,a.dyn_ltree,a.dyn_dtree)),p(a),d&&q(a)}function F(a,b,c){return a.pending_buf[a.d_buf+2*a.last_lit]=b>>>8&255,a.pending_buf[a.d_buf+2*a.last_lit+1]=255&b,a.pending_buf[a.l_buf+a.last_lit]=255&c,a.last_lit++,0===b?a.dyn_ltree[2*c]++:(a.matches++,b--,a.dyn_ltree[2*(ja[c]+R+1)]++,a.dyn_dtree[2*g(b)]++),a.last_lit===a.lit_bufsize-1}var G=a("../utils/common"),H=4,I=0,J=1,K=2,L=0,M=1,N=2,O=3,P=258,Q=29,R=256,S=R+1+Q,T=30,U=19,V=2*S+1,W=15,X=16,Y=7,Z=256,$=16,_=17,aa=18,ba=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],ca=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],da=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],ea=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],fa=512,ga=new Array(2*(S+2));d(ga);var ha=new Array(2*T);d(ha);var ia=new Array(fa);d(ia);var ja=new Array(P-O+1);d(ja);var ka=new Array(Q);d(ka);var la=new Array(T);d(la);var ma,na,oa,pa=!1;c._tr_init=B,c._tr_stored_block=C,c._tr_flush_block=E,c._tr_tally=F,c._tr_align=D},{"../utils/common":62}],74:[function(a,b,c){"use strict";function d(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}b.exports=d},{}]},{},[10])(10)}); \ No newline at end of file diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/about-team.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/about-team.inc index fbafd90ebe..ff1c6103da 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/about-team.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/about-team.inc @@ -32,6 +32,7 @@ [%- CASE 'meeting_facilitator' -%]Meeting facilitator [%- CASE 'ktd' -%]Developer tooling [%- CASE 'website' -%]Website administrator + [%- CASE 'security_manager' -%]Security release manager [%- CASE -%]MISSING MAP FOR ROLE: [% role.key | html %] [%- END -%] [%- IF ex %] - [% ex | html %][% END -%] @@ -78,6 +79,12 @@

This is the team who are responsible for the next release of Koha and the ongoing maintenance of your currently installed Koha version. They will be in these roles up until [% t.release_date | $KohaDates %], when the next team will be elected.

+ [% FOREACH s IN t.security_manager %] +
  • Security release manager: + [% INCLUDE person p=s %] +
  • + [% END %] + [% FOREACH m IN t.maintainer %] [% IF m.version == ( v ) %]
  • Release maintainer: diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/acquisitions-toolbar.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/acquisitions-toolbar.inc index 67488b141c..d4f28c3a2c 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/acquisitions-toolbar.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/acquisitions-toolbar.inc @@ -31,7 +31,7 @@ [% IF CAN_user_acquisition_order_receive && basketcount && active %] [% END %] - [% ELSE %] + [% ELSIF ( CAN_user_acquisition_vendors_manage ) %] [% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/background_jobs/import_from_kbart_file.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/background_jobs/import_from_kbart_file.inc index 2cc00b2002..3d1ac034c1 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/background_jobs/import_from_kbart_file.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/background_jobs/import_from_kbart_file.inc @@ -67,7 +67,7 @@ [% END %] [% END %] - [% Asset.js("js/job_progress.js") | $raw %] + [% BLOCK js %] [% INCLUDE 'str/job_progress.inc' job_id=job.id %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/biblio-title.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/biblio-title.inc index 66ebc8527a..694f569f57 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/biblio-title.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/biblio-title.inc @@ -1,3 +1,4 @@ +[%- USE To -%] [%- IF link && ! biblio %][% link = 0 %][% END %] [%- IF ( link ) -%] @@ -8,23 +9,23 @@ [%- ELSIF !biblio.title -%] No title [%- ELSE -%] - [% biblio.title | html %] + [% biblio.title | html | $To %] [%- END -%] [%- IF ( biblio.medium ) -%] - [%- biblio.medium | html -%] + [%- biblio.medium | html | $To -%] [%- END -%] [%- FOREACH subtitle IN biblio.subtitle.split(' \\| ') -%][%- IF Koha.Preference('marcflavour')=='UNIMARC' -%],[%- END -%] - [%- subtitle | html -%] + [%- subtitle | html | $To -%] [%- END -%] [%- part_numbers = biblio.part_number.split(' \\| ') -%] [%- part_names = biblio.part_name.split(' \\| ') -%] [%- i = 0 -%] [%- WHILE ( part_numbers.$i.defined || part_names.$i.defined ) -%] [%- IF ( part_numbers.$i.defined ) -%] - [%- part_numbers.$i | html -%] + [%- part_numbers.$i | html | $To -%] [%- END -%] [%- IF ( part_names.$i.defined ) -%] - [%- part_names.$i | html -%] + [%- part_names.$i | html | $To -%] [%- END -%] [%- i = i + 1 -%] [%- END -%] diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/blocking_errors.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/blocking_errors.inc index a4fd22249e..20376d1ed8 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/blocking_errors.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/blocking_errors.inc @@ -22,9 +22,11 @@ [% CASE 'budget_is_locked' %]
    The budget is locked, fund creation is not possible.
    [% CASE 'missing_es_modules' %] -
    Necessary Elasticsearch packages are not installed on your server. Please contact your server admin if you wish to configure Elasticsearch
    +
    Necessary Elasticsearch packages are not installed on your server. Please contact your server admin if you wish to configure Elasticsearch.
    [% CASE 'insufficient_permission' %]
    You do not have sufficient permission to continue.
    + [% CASE 'duplicate_tagfield' %] +
    MARC field not added to MARC bibliographic framework. MARC tag already exists in framework.
    [% CASE %]
    [% blocking_error | html %]
    [% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/calendar.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/calendar.inc index 9f1cdb6ceb..0565b0faac 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/calendar.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/calendar.inc @@ -74,7 +74,7 @@ .addClass("clear_date") .on("click", function(e){ e.preventDefault(); - instance.input.flatpickr().clear(); + instance.clear(); }) .addClass("fa fa-fw fa-times") .attr("aria-hidden", true) @@ -110,6 +110,10 @@ new Maskito( instance.altInput, maskitoOptions ); }, onChange: function( selectedDates, dateText, instance) { + if (selectedDates.length === 0) { + return; + } + var thisInput = instance.input; let accepts_time = $(thisInput).data('flatpickr-enable-time'); let accepts_period = $(thisInput).data('flatpickr-period'); diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.json.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.json.inc index 08ca9f76d0..2a584db8bd 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.json.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.json.inc @@ -13,20 +13,20 @@ "[% FILTER escape_quotes ~%]
    [% INCLUDE 'biblio-title.inc' | trim | collapse %][% IF ( Koha.Preference( 'marcflavour' ) == 'UNIMARC' && biblio.author ) %] by[% END %] [% biblio.author | html %] [%~ END %]", - "[% (biblioitem.publicationyear || biblio.copyrightdate) | html %]", + "[% (biblioitem.publicationyear || biblio.copyrightdate) | html | $To %]", "[% biblioitem.publishercode | html | $To %]", - "[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.ccode', authorised_value => item.ccode ) | html %]", + "[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.ccode', authorised_value => item.ccode ) | html | $To %]", "[% FILTER escape_quotes ~%] - [% item.barcode | html %] + [% item.barcode | html | $To %] [%~ END %]", "[% item.itemnumber | html %]", - "[% item.enumchron | html %]", - "[% item.itemcallnumber | html %]", + "[% item.enumchron | html | $To %]", + "[% item.itemcallnumber | html | $To %]", "[% Branches.GetName(item.homebranch) | html %]", "[% Branches.GetName(item.holdingbranch) | html %]", "[% AuthorisedValues.GetDescriptionByKohaField( frameworkcode => biblio.frameworkcode, kohafield => 'items.location', authorised_value => item.location) | html %]", "[% ItemTypes.GetDescription(item.itype) | html %]", - "[% item.stocknumber | html %]", + "[% item.stocknumber | html | $To %]", "[% AuthorisedValues.GetDescriptionByKohaField( frameworkcode => biblio.frameworkcode, kohafield => 'items.notforloan', authorised_value => item.notforloan) | html %]", "[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.itemlost', authorised_value => item.itemlost ) || "" | html %]", "[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.withdrawn', authorised_value => item.withdrawn ) || "" | html %]", diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-ui.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-ui.inc index 338c7d5dee..47474940f3 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-ui.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-ui.inc @@ -878,7 +878,7 @@ require( [ 'koha-backend', 'search', 'macros', 'marc-editor', 'marc-record', 'pr $("#macro-toolbar").prepend($convert); } let options = { - url: "/api/v1/advanced_editor/macros/", + url: "/api/v1/advanced_editor/macros/?_per_page=-1", method: "GET", contentType: "application/json", }; diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-widgets-marc21.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-widgets-marc21.inc index 26cadeda16..1a87de386f 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-widgets-marc21.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-widgets-marc21.inc @@ -152,8 +152,10 @@ require( [ 'koha-backend', 'widget', 'text-marc' ], function( KohaBackend, Widge $( this.node ) .find('.control-number-widget-assign').click( function() { var sequence = $( widget.node ).find('.control-number-widget-sequence').val(); + const csrf_token = document.querySelector('meta[name="csrf-token"]').getAttribute('content'); $.post( - '/cgi-bin/koha/svc/cataloguing/control_num_sequences/' + sequence + '/cgi-bin/koha/svc/cataloguing/control_num_sequences/' + sequence, + { csrf_token: csrf_token } ).done( function( result ) { if ( result.next_value ) widget.setControlNumber( result.next_value ); } ); diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers/tables/items/catalogue_detail.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers/tables/items/catalogue_detail.inc index 338296467b..714e60282d 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers/tables/items/catalogue_detail.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers/tables/items/catalogue_detail.inc @@ -120,6 +120,24 @@ } } + function update_columns_visibility(settings){ + let table = settings.oInstance.api(); + table.columns().visible(true); + table.columns().every(function(i){ + let is_empty = true; + let nodes = this.nodes(); + nodes.each((td, ii) => { + if ( $(td).html() !== '' ) { + is_empty = false; + return; + } + }); + if ( is_empty ) { + table.columns(i).visible(false); + } + }); + } + $(document).ready(function() { $(".SelectAll").on("click",function(e){ @@ -210,7 +228,7 @@ [%# In case or SeparateHoldings we may need to display the number of biblios in each tab %] [%# Do we need separate/new endpoints or do we hack the somewhere client-side? %] let item_table_url = "/api/v1/biblios/[% biblio.biblionumber | uri %]/items?"; - let embed = ["+strings,checkout,checkout.patron,transfer,transfer+strings,first_hold,first_hold+strings,first_hold.patron,first_hold.desk"]; + let embed = ["+strings,home_library,holding_library,checkout,checkout.patron,transfer,transfer+strings,first_hold,first_hold+strings,first_hold.patron,first_hold.desk"]; [% IF Koha.Preference('LocalCoverImages') %] embed.push('cover_image_ids'); [% END %] @@ -223,9 +241,7 @@ [% IF Koha.Preference('UseRecalls') %] embed.push('recall', 'recall+strings', 'recall.patron') [% END %] - [% IF bundlesEnabled %] - embed.push('in_bundle', 'bundle_host', 'bundle_items_lost+count', 'bundle_items_not_lost+count'); - [% END %] + embed.push('in_bundle', 'bundle_host', 'bundle_host.biblio', 'bundle_items_lost+count', 'bundle_items_not_lost+count'); [% IF Koha.Preference('UseCourseReserves') %] embed.push('course_item.course_reserves.course'); [% END %] @@ -358,7 +374,7 @@ }, [% END %] { - data: "me.holding_library_id", + data: "holding_library.name:me.holding_library_id", className: "location", searchable: true, orderable: true, @@ -367,7 +383,7 @@ } }, { - data: "me.home_library_id", + data: "home_library.name:me.home_library_id", className: "homebranch", searchable: true, orderable: true, @@ -493,7 +509,7 @@ nodes += '%s'.format(escape_str(damaged_lib)); } - if ( row.not_for_loan_status || item_types_notforloan[row.item_type_id] ) { + if ( row.not_for_loan_status || item_types_notforloan.get(row.item_type_id) ) { let not_for_loan_lib = av_not_for_loan.get(row.not_for_loan_status.toString()); nodes += '%s'.format(_("Not for loan")) + ( not_for_loan_lib ? ' (%s)'.format(escape_str(not_for_loan_lib)) : '' ) + ''; } @@ -533,7 +549,7 @@ } [% END %] - if ( ! ( row.not_for_loan_status || item_types_notforloan[row.item_type_id] || row.checked_out_date || row.lost_status || row.withdrawn || row.damaged_status || row.transfer || row.first_hold || row.recall ) ) { + if ( ! ( row.not_for_loan_status || item_types_notforloan.get(row.item_type_id) || row.checked_out_date || row.lost_status || row.withdrawn || row.damaged_status || row.transfer || row.first_hold || row.recall ) ) { nodes += ' %s'.format(_("Available")) } @@ -541,11 +557,9 @@ nodes += '(%s)'.format(escape_str(av_restricted.get(row.restricted_status.toString()))); } - [% IF bundlesEnabled %] - if ( row.in_bundle ) { - nodes += '%s'.format(_("In bundle: %s").format($biblio_to_html(row.bundle_host.biblio, { link: true }))); - } - [% END %] + if ( row.in_bundle ) { + nodes += '%s'.format(_("In bundle: %s").format($biblio_to_html(row.bundle_host.biblio, { link: true }))); + } return nodes; } }, @@ -556,7 +570,7 @@ searchable: true, orderable: true, render: function (data, type, row, meta) { - return $date(row.last_seen_date); + return $datetime(row.last_seen_date); } }, { @@ -759,7 +773,7 @@ nodes += '
    '; nodes += ' %s'.format(row.biblio_id, row.item_id, _("Edit")); nodes += ' '; nodes += '
    '; [% ELSE %] @@ -779,20 +793,6 @@ [% END %] ], initComplete: function( settings, json ){ - let table = settings.oInstance.api(); - table.columns().every(function(i){ - let is_empty = true; - let nodes = this.nodes(); - nodes.each((td, ii) => { - if ( $(td).html() !== '' ) { - is_empty = false; - return; - } - }); - if ( is_empty ) { - table.columns(i).visible(false); - } - }); [% IF StaffDetailItemSelection %] itemSelectionBuildActionLinks(tab_id); [% END %] @@ -835,6 +835,10 @@ }); [% END %] + if ( api.data().length ) { + update_columns_visibility(settings); + } + if ( drawcallback ) { drawcallback(this); } }, [% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/js-patron-format.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/js-patron-format.inc index ae27dd09ba..69b472d97b 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/js-patron-format.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/js-patron-format.inc @@ -37,7 +37,7 @@ } if ( name.replace(' ', '').length == 0 ) { - return _("A patron from library %s".format(patron.library.name)); + return _("A patron from %s".format(patron.library.name)); } if ( config && config.hide_patron_name ) { diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-search.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/patron-search.inc index 858dd2f483..74ec8d5a4f 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-search.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/patron-search.inc @@ -316,9 +316,8 @@ // Build the aLengthMenu let aLengthMenu = [ - [% Koha.Preference('PatronsPerPage') | html %], 10, 20, 50, 100, -1 + ...new Set([[% Koha.Preference('PatronsPerPage') | html %], 10, 20, 50, 100, -1]) ]; - jQuery.unique(aLengthMenu); aLengthMenu.sort(function( a, b ){ // Put "All" at the end if ( a == -1 ) { @@ -381,7 +380,7 @@ [% default_sort_column = "name" %] [% END %] [% SET order_column_index = 0 %] - [% SET embed = ['extended_attributes'] %] + [% SET embed = ['extended_attributes','library'] %] patrons_table = $("#[% table_id | html %]").kohaTable({ "ajax": { "url": patron_search_url, @@ -532,15 +531,14 @@ } [% CASE 'branch' %] { - "data": "library_id", + "data": "library.name:me.library_id", "searchable": true, "orderable": true, "render": function( data, type, row, meta ) { - let library_name = libraries_map[data].branchname - if( !singleBranchMode && data == logged_in_library_id ) { - return "" + escape_str(library_name) + ""; + if( !singleBranchMode && row.library.library_id == logged_in_library_id ) { + return "" + escape_str(row.library.name) + ""; } else { - return escape_str(library_name); + return escape_str(row.library.name); } } } @@ -712,7 +710,7 @@ patron_search_form.find(".clear_search").on("click",function(e){ e.preventDefault(); clearFilters(); - patron_search_form.find(".searchpattern").parent().hide(); + parent_block.find(".searchpattern").parent().hide(); }); if ( !defer_loading ) { @@ -786,8 +784,7 @@ searched += paron_search_form.find("select[name='sort2_filter']").val(); } } - patron_search_form.find(".searchpattern").text(searched); - patron_search_form.find(".searchpattern").parent().show(); + parent_block.find(".searchpattern").text(searched).parent().show(); } function filter() { diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/patron_messages.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/patron_messages.inc index ea611abdce..9d373d1c26 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/patron_messages.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/patron_messages.inc @@ -101,7 +101,7 @@ [% IF ( odues ) %]
  • - Overdues: Patron has ITEMS OVERDUE See highlighted items below + Overdues: Patron has ITEMS OVERDUE See highlighted items below
  • [% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/reports-toolbar.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/reports-toolbar.inc index fcad9be406..3105d0e8df 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/reports-toolbar.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/reports-toolbar.inc @@ -78,7 +78,7 @@