From srdjan at catalyst.net.nz Wed Jun 1 04:15:04 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Wed, 1 Jun 2016 14:15:04 +1200 Subject: [Koha-patches] [PATCH] Bug 16436 - Allow action logs to be logged to the koha log file Message-ID: <1464747304-27048-1-git-send-email-srdjan@catalyst.net.nz> From: Kyle M Hall Test Plan: 1) Ensure that your Koha::Logger configuration is in good working order 2) Apply this patch 3) Modify the first line of your log4perl.conf file from: log4perl.logger.intranet = WARN, INTRANET to log4perl.logger.intranet = INFO, INTRANET 4) Change a system preference setting 5) Note the new line in your log file! Signed-off-by: Srdjan --- C4/Log.pm | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/C4/Log.pm b/C4/Log.pm index de5f1d0..cff1e6f 100644 --- a/C4/Log.pm +++ b/C4/Log.pm @@ -24,8 +24,11 @@ package C4::Log; use strict; use warnings; +use JSON qw( to_json ); + use C4::Context; use Koha::DateUtils; +use Koha::Logger; use vars qw(@ISA @EXPORT); @@ -77,6 +80,26 @@ sub logaction { my $sth=$dbh->prepare("Insert into action_logs (timestamp,user,module,action,object,info) values (now(),?,?,?,?,?)"); $sth->execute($usernumber,$modulename,$actionname,$objectnumber,$infos); $sth->finish; + + my $logger = Koha::Logger->get( + { + interface => 'intranet', + category => "ActionLogs.$modulename.$actionname" + } + ); + $logger->info( + sub { + "ACTION LOG: " . to_json( + { + user => $usernumber, + module => $modulename, + action => $actionname, + object => $objectnumber, + info => $infos + } + ); + } + ); } =item cronlogaction @@ -144,10 +167,10 @@ sub displaylog { SELECT action_logs.timestamp, action_logs.action, action_logs.info, borrowers.cardnumber, borrowers.surname, borrowers.firstname, borrowers.userid, biblio.biblionumber, biblio.title, biblio.author - FROM action_logs - LEFT JOIN borrowers ON borrowers.borrowernumber=action_logs.user + FROM action_logs + LEFT JOIN borrowers ON borrowers.borrowernumber=action_logs.user LEFT JOIN biblio ON action_logs.object=biblio.biblionumber - WHERE action_logs.module = 'cataloguing' + WHERE action_logs.module = 'cataloguing' |; my %filtermap = (); if ($modulename eq "catalogue" or $modulename eq "acqui") { @@ -158,13 +181,13 @@ sub displaylog { ); } elsif ($modulename eq "members") { $strsth=qq| - SELECT action_logs.timestamp, action_logs.action, action_logs.info, + SELECT action_logs.timestamp, action_logs.action, action_logs.info, borrowers.cardnumber, borrowers.surname, borrowers.firstname, borrowers.userid, bor2.cardnumber, bor2.surname, bor2.firstname, bor2.userid - FROM action_logs - LEFT JOIN borrowers ON borrowers.borrowernumber=action_logs.user + FROM action_logs + LEFT JOIN borrowers ON borrowers.borrowernumber=action_logs.user LEFT JOIN borrowers as bor2 ON action_logs.object=bor2.borrowernumber - WHERE action_logs.module = 'members' + WHERE action_logs.module = 'members' |; %filtermap = ( user => 'borrowers.surname', @@ -204,7 +227,7 @@ sub displaylog { $logs = GetLogs($datefrom,$dateto,$user,\@modules,$action,$object,$info); -Return: +Return: C<$logs> is a ref to a hash which containts all columns from action_logs =cut -- 2.7.4 From srdjan at catalyst.net.nz Wed Jun 1 06:33:07 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Wed, 1 Jun 2016 16:33:07 +1200 Subject: [Koha-patches] [PATCH] bug_15562: Multi-host helper for plack installations Message-ID: <1464755587-8991-1-git-send-email-srdjan@catalyst.net.nz> Sort of an apocalypse * C4::Context->new() must be called with at least config file param. If you want current context, call C4::Context->current(). C4::Context->some_method() will still work as is. * Koha::Database->new_schema() now takes optional context param. * C4::Context->set_context() and restore_context() are synched with database set_schema() and restore_schema(). Created run_within_context() that wraps set_context() and restore_context() around code. * Created Koha::Handler::Plack* to facilitate running same code within different (database) contexts. * This initial version does not run with memcached turned on. Next patch will correct that. https://bugs.koha-community.org/show_bug.cgi?id=15562 Signed-off-by: Kyle M Hall --- C4/Auth_with_cas.pm | 2 +- C4/Auth_with_ldap.pm | 2 +- C4/Context.pm | 352 ++++++++++++++--------------- Koha/Cache.pm | 18 +- Koha/Database.pm | 38 +++- Koha/Handler/Plack.pm | 163 +++++++++++++ Koha/Handler/Plack/CGI.pm | 228 +++++++++++++++++++ about.pl | 2 +- admin/systempreferences.pl | 2 +- misc/cronjobs/check-url.pl | 2 +- misc/plack/koha-multi.psgi | 29 +++ misc/translator/LangInstaller.pm | 4 +- t/Koha_Handler_Plack.t | 136 +++++++++++ t/conf/dummy/koha-conf.xml | 7 + t/conf/koha1/koha-conf.xml | 7 + t/conf/koha2/koha-conf.xml | 5 + t/db_dependent/Amazon.t | 2 +- t/db_dependent/Context.t | 2 +- t/db_dependent/Template/Plugin/KohaDates.t | 2 +- t/db_dependent/XISBN.t | 2 +- t/db_dependent/sysprefs.t | 13 +- 21 files changed, 804 insertions(+), 214 deletions(-) create mode 100644 Koha/Handler/Plack.pm create mode 100644 Koha/Handler/Plack/CGI.pm create mode 100644 misc/plack/koha-multi.psgi create mode 100644 t/Koha_Handler_Plack.t create mode 100644 t/conf/dummy/koha-conf.xml create mode 100644 t/conf/koha1/koha-conf.xml create mode 100644 t/conf/koha2/koha-conf.xml diff --git a/C4/Auth_with_cas.pm b/C4/Auth_with_cas.pm index c9174da..f78e3b5 100644 --- a/C4/Auth_with_cas.pm +++ b/C4/Auth_with_cas.pm @@ -36,7 +36,7 @@ BEGIN { @ISA = qw(Exporter); @EXPORT = qw(check_api_auth_cas checkpw_cas login_cas logout_cas login_cas_url); } -my $context = C4::Context->new() or die 'C4::Context->new failed'; +my $context = C4::Context->current() or die 'No current context'; my $defaultcasserver; my $casservers; my $yamlauthfile = C4::Context->config('intranetdir') . "/C4/Auth_cas_servers.yaml"; diff --git a/C4/Auth_with_ldap.pm b/C4/Auth_with_ldap.pm index c50df76..0f7a174 100644 --- a/C4/Auth_with_ldap.pm +++ b/C4/Auth_with_ldap.pm @@ -53,7 +53,7 @@ sub ldapserver_error { } use vars qw($mapping @ldaphosts $base $ldapname $ldappassword); -my $context = C4::Context->new() or die 'C4::Context->new failed'; +my $context = C4::Context->current() or die 'No current context'; my $ldap = C4::Context->config("ldapserver") or die 'No "ldapserver" in server hash from KOHA_CONF: ' . $ENV{KOHA_CONF}; my $prefhost = $ldap->{hostname} or die ldapserver_error('hostname'); my $base = $ldap->{base} or die ldapserver_error('base'); diff --git a/C4/Context.pm b/C4/Context.pm index c80647a..63a71d6 100644 --- a/C4/Context.pm +++ b/C4/Context.pm @@ -31,7 +31,7 @@ BEGIN { eval {C4::Context->dbh();}; if ($@){ $debug_level = 1; - } + } else { $debug_level = C4::Context->preference("DebugLevel"); } @@ -49,7 +49,7 @@ BEGIN { # a little example table with various version info"; print "

Koha error

-

The following fatal error has occurred:

+

The following fatal error has occurred:

$msg
@@ -63,11 +63,11 @@ BEGIN { } elsif ($debug_level eq "1"){ print "

Koha error

-

The following fatal error has occurred:

+

The following fatal error has occurred:

$msg
"; } else { print "

production mode - trapped fatal error

"; - } + } print ""; } #CGI::Carp::set_message(\&handle_errors); @@ -112,6 +112,7 @@ use Koha::Cache; use POSIX (); use DateTime::TimeZone; use Module::Load::Conditional qw(can_load); +use Data::Dumper; use Carp; use C4::Boolean; @@ -179,10 +180,6 @@ environment variable to the pathname of a configuration file to use. # file (/etc/koha/koha-conf.xml). # dbh # A handle to the appropriate database for this context. -# dbh_stack -# Used by &set_dbh and &restore_dbh to hold other database -# handles for this context. -# Zconn # A connection object for the Zebra server # Koha's main configuration file koha-conf.xml @@ -191,7 +188,7 @@ environment variable to the pathname of a configuration file to use. # 1. Path supplied via use C4::Context '/path/to/koha-conf.xml' # 2. Path supplied in KOHA_CONF environment variable. # 3. Path supplied in INSTALLED_CONFIG_FNAME, as long -# as value has changed from its default of +# as value has changed from its default of # '__KOHA_CONF_DIR__/koha-conf.xml', as happens # when Koha is installed in 'standard' or 'single' # mode. @@ -201,52 +198,25 @@ environment variable to the pathname of a configuration file to use. use constant CONFIG_FNAME => "/etc/koha/koha-conf.xml"; # Default config file, if none is specified - + my $INSTALLED_CONFIG_FNAME = '__KOHA_CONF_DIR__/koha-conf.xml'; # path to config file set by installer # __KOHA_CONF_DIR__ is set by rewrite-confg.PL # when Koha is installed in 'standard' or 'single' - # mode. If Koha was installed in 'dev' mode, + # mode. If Koha was installed in 'dev' mode, # __KOHA_CONF_DIR__ is *not* rewritten; instead - # developers should set the KOHA_CONF environment variable - -$context = undef; # Initially, no context is set - at context_stack = (); # Initially, no saved contexts - - -=head2 read_config_file - -Reads the specified Koha config file. - -Returns an object containing the configuration variables. The object's -structure is a bit complex to the uninitiated ... take a look at the -koha-conf.xml file as well as the XML::Simple documentation for details. Or, -here are a few examples that may give you what you need: + # developers should set the KOHA_CONF environment variable -The simple elements nested within the element: + at context_stack = (); # Initially, no saved contexts - my $pass = $koha->{'config'}->{'pass'}; +=head2 current -The elements: - - my $listen = $koha->{'listen'}->{'biblioserver'}->{'content'}; - -The elements nested within the element: - - my $ccl2rpn = $koha->{'server'}->{'biblioserver'}->{'cql2rpn'}; - -Returns undef in case of error. +Returns the current context =cut -sub read_config_file { # Pass argument naming config file to read - my $koha = XMLin(shift, keyattr => ['id'], forcearray => ['listen', 'server', 'serverinfo'], suppressempty => ''); - - if ($ismemcached) { - $memcached->set('kohaconf',$koha); - } - - return $koha; # Return value: ref-to-hash holding the configuration +sub current { + return $context; } =head2 ismemcached @@ -274,6 +244,15 @@ sub memcached { } } +sub db_driver { + my $self = shift; + + $self = $context unless ref ($self); + return unless $self; + + return $self->{db_driver}; +} + =head2 db_scheme2dbi my $dbd_driver_name = C4::Context::db_schema2dbi($scheme); @@ -294,32 +273,85 @@ sub import { # Create the default context ($C4::Context::Context) # the first time the module is called # (a config file can be optionaly passed) + # If ":no_config" is passed, no config load will be attempted + # Config file defaults to either the file given by the $KOHA_CONF + # environment variable, or /etc/koha/koha-conf.xml. + # It saves the context values in the declared memcached server(s) + # if currently available and uses those values until them expire and + # re-reads them. + + my ($pkg,$config_file) = @_ ; # default context already exists? return if $context; + if ($ismemcached) { + # retrieve from memcached + if (my $self = $memcached->get('kohaconf')) { + $context = $self; + return; + } + } + + # check that the specified config file exists and is not empty + undef $config_file if defined $config_file && + !( ref($config_file) || openhandle($config_file) || -s $config_file ); + # Figure out a good config file to load if none was specified. + if (!defined($config_file)) + { + # If the $KOHA_CONF environment variable is set, use + # that. Otherwise, use the built-in default. + if ($ENV{'KOHA_CONF'} and ref($ENV{'KOHA_CONF'}) || -s $ENV{"KOHA_CONF"}) { + $config_file = $ENV{"KOHA_CONF"}; + } elsif ($INSTALLED_CONFIG_FNAME !~ /__KOHA_CONF_DIR/ and -s $INSTALLED_CONFIG_FNAME) { + # NOTE: be careful -- don't change __KOHA_CONF_DIR in the above + # regex to anything else -- don't want installer to rewrite it + $config_file = $INSTALLED_CONFIG_FNAME; + } elsif (-s CONFIG_FNAME) { + $config_file = CONFIG_FNAME; + } else { + die "unable to locate Koha configuration file koha-conf.xml"; + } + } + # no ? so load it! - my ($pkg,$config_file) = @_ ; + return if $config_file && $config_file eq ":no_config"; my $new_ctx = __PACKAGE__->new($config_file); return unless $new_ctx; # if successfully loaded, use it by default - $new_ctx->set_context; - 1; + $context = $new_ctx; + + if ($ismemcached) { + $memcached->set('kohaconf',$new_ctx); + } } +use Scalar::Util qw(openhandle); =head2 new - $context = new C4::Context; $context = new C4::Context("/path/to/koha-conf.xml"); Allocates a new context. Initializes the context from the specified -file, which defaults to either the file given by the C<$KOHA_CONF> -environment variable, or F. +file. -It saves the koha-conf.xml values in the declared memcached server(s) -if currently available and uses those values until them expire and -re-reads them. +XML structure is a bit complex to the uninitiated ... take a look at the +koha-conf.xml file as well as the XML::Simple documentation for details. Or, +here are a few examples that may give you what you need: + +The simple elements nested within the element: + + my $pass = $koha->{'config'}->{'pass'}; + +The elements: + + my $listen = $koha->{'listen'}->{'biblioserver'}->{'content'}; + +The elements nested within the element: + + my $ccl2rpn = $koha->{'server'}->{'biblioserver'}->{'cql2rpn'}; + +Returns undef in case of error. C<&new> does not set this context as the new default context; for that, use C<&set_context>. @@ -331,46 +363,22 @@ that, use C<&set_context>. # 2004-08-10 A. Tarallo: Added check if the conf file is not empty sub new { my $class = shift; - my $conf_fname = shift; # Config file to load - my $self = {}; - - # check that the specified config file exists and is not empty - undef $conf_fname unless - (defined $conf_fname && -s $conf_fname); - # Figure out a good config file to load if none was specified. - if (!defined($conf_fname)) - { - # If the $KOHA_CONF environment variable is set, use - # that. Otherwise, use the built-in default. - if (exists $ENV{"KOHA_CONF"} and $ENV{'KOHA_CONF'} and -s $ENV{"KOHA_CONF"}) { - $conf_fname = $ENV{"KOHA_CONF"}; - } elsif ($INSTALLED_CONFIG_FNAME !~ /__KOHA_CONF_DIR/ and -s $INSTALLED_CONFIG_FNAME) { - # NOTE: be careful -- don't change __KOHA_CONF_DIR in the above - # regex to anything else -- don't want installer to rewrite it - $conf_fname = $INSTALLED_CONFIG_FNAME; - } elsif (-s CONFIG_FNAME) { - $conf_fname = CONFIG_FNAME; - } else { - warn "unable to locate Koha configuration file koha-conf.xml"; - return; - } - } - - if ($ismemcached) { - # retrieve from memcached - $self = $memcached->get('kohaconf'); - if (not defined $self) { - # not in memcached yet - $self = read_config_file($conf_fname); - } - } else { - # non-memcached env, read from file - $self = read_config_file($conf_fname); - } - - $self->{"config_file"} = $conf_fname; - warn "read_config_file($conf_fname) returned undef" if !defined($self->{"config"}); - return if !defined($self->{"config"}); + my $conf_fname = shift or croak "No conf"; + my $namespace = shift; + + my $self = XMLin( + $conf_fname, + keyattr => ['id'], + forcearray => ['listen', 'server', 'serverinfo'], + suppressempty => '', + ); + die "Invalid config ".(ref($conf_fname) ? $$conf_fname : $conf_fname).": ".Dumper($self) + unless ref($self) && $self->{"config"}; + + $self->{config_file} = $conf_fname; + $self->{namespace} = $namespace; + $self->{use_syspref_cache} = 1; + $self->{syspref_cache} = Koha::Cache->new({namespace => $namespace}); $self->{"Zconn"} = undef; # Zebra Connections $self->{"marcfromkohafield"} = undef; # the hash with relations between koha table fields and MARC field/subfield @@ -386,7 +394,6 @@ sub new { =head2 set_context - $context = new C4::Context; $context->set_context(); or set_context C4::Context $context; @@ -419,17 +426,21 @@ sub set_context if (ref($self) eq "") { # Class method. The new context is the next argument. - $new_context = shift; + $new_context = shift or croak "No new context"; } else { # Instance method. The new context is $self. $new_context = $self; } - # Save the old context, if any, on the stack - push @context_stack, $context if defined($context); + # undef $new_context->{schema} if $new_context->{schema} && !$new_context->{schema}->ping + my $schema = $new_context->{schema} ||= Koha::Database->new_schema($new_context); + + # Save the old context on the stack + push @context_stack, $context; # Set the new context $context = $new_context; + Koha::Database->set_schema($schema); } =head2 restore_context @@ -445,19 +456,38 @@ sub restore_context { my $self = shift; - if ($#context_stack < 0) - { - # Stack underflow. - die "Context stack underflow"; - } - # Pop the old context and set it. $context = pop @context_stack; + Koha::Database->restore_schema(); # FIXME - Should this return something, like maybe the context # that was current when this was called? } +=head2 run_within_context + + $context->run_within_context(sub {...}); + +Runs code within context + +=cut + +#' +sub run_within_context +{ + my $self = shift; + my $code = shift or croak "No code"; + + $self->set_context; + + local $@; + my $ret = eval { $code->(@_) }; + my $died = $@; + $self->restore_context; + die $died if $died; + return $ret; +} + =head2 config $value = C4::Context->config("config_variable"); @@ -474,26 +504,32 @@ Cnew> will not return it. =cut sub _common_config { - my $var = shift; - my $term = shift; - return if !defined($context->{$term}); + my $self = shift; + my $var = shift; + my $term = shift; + + $self = $context unless ref $self; + return if !defined($self->{$term}); # Presumably $self->{$term} might be # undefined if the config file given to &new # didn't exist, and the caller didn't bother # to check the return value. # Return the value of the requested config variable - return $context->{$term}->{$var}; + return $self->{$term}->{$var}; } sub config { - return _common_config($_[1],'config'); + my $self = shift; + return $self->_common_config($_[0],'config'); } sub zebraconfig { - return _common_config($_[1],'server'); + my $self = shift; + return $self->_common_config($_[0],'server'); } sub ModZebrations { - return _common_config($_[1],'serverinfo'); + my $self = shift; + return $self->_common_config($_[0],'serverinfo'); } =head2 preference @@ -512,10 +548,9 @@ with this method. =cut -my $syspref_cache = Koha::Cache->get_instance(); -my $use_syspref_cache = 1; sub preference { my $self = shift; + $self = $context unless ref $self; my $var = shift; # The system preference to return $var = lc $var; @@ -523,8 +558,8 @@ sub preference { return $ENV{"OVERRIDE_SYSPREF_$var"} if defined $ENV{"OVERRIDE_SYSPREF_$var"}; - my $cached_var = $use_syspref_cache - ? $syspref_cache->get_from_cache("syspref_$var") + my $cached_var = $self->{use_syspref_cache} + ? $self->{syspref_cache}->get_from_cache("syspref_$var") : undef; return $cached_var if defined $cached_var; @@ -532,8 +567,8 @@ sub preference { eval { $syspref = Koha::Config::SysPrefs->find( lc $var ) }; my $value = $syspref ? $syspref->value() : undef; - if ( $use_syspref_cache ) { - $syspref_cache->set_in_cache("syspref_$var", $value); + if ( $self->{use_syspref_cache} ) { + $self->{syspref_cache}->set_in_cache("syspref_$var", $value); } return $value; } @@ -556,7 +591,8 @@ default behavior. sub enable_syspref_cache { my ($self) = @_; - $use_syspref_cache = 1; + $self = $context unless ref $self; + $self->{use_syspref_cache} = 1; # We need to clear the cache to have it up-to-date $self->clear_syspref_cache(); } @@ -572,7 +608,8 @@ used with Plack and other persistent environments. sub disable_syspref_cache { my ($self) = @_; - $use_syspref_cache = 0; + $self = $context unless ref $self; + $self->{use_syspref_cache} = 0; $self->clear_syspref_cache(); } @@ -587,8 +624,10 @@ will not be seen by this process. =cut sub clear_syspref_cache { - return unless $use_syspref_cache; - $syspref_cache->flush_all; + my ($self) = @_; + $self = $context unless ref $self; + return unless $self->{use_syspref_cache}; + $self->{syspref_cache}->flush_all; } =head2 set_preference @@ -604,6 +643,7 @@ preference. sub set_preference { my ( $self, $variable, $value, $explanation, $type, $options ) = @_; + $self = $context unless ref $self; $variable = lc $variable; @@ -639,8 +679,8 @@ sub set_preference { )->store(); } - if ( $use_syspref_cache ) { - $syspref_cache->set_in_cache( "syspref_$variable", $value ); + if ( $self->{use_syspref_cache} ) { + $self->{syspref_cache}->set_in_cache( "syspref_$variable", $value ); } return $syspref; @@ -658,10 +698,11 @@ was no syspref of the name. sub delete_preference { my ( $self, $var ) = @_; + $self = $context unless ref $self; if ( Koha::Config::SysPrefs->find( $var )->delete ) { - if ( $use_syspref_cache ) { - $syspref_cache->clear_from_cache("syspref_$var"); + if ( $self->{use_syspref_cache} ) { + $self->{syspref_cache}->clear_from_cache("syspref_$var"); } return 1; @@ -675,7 +716,7 @@ sub delete_preference { Returns a connection to the Zebra database -C<$self> +C<$self> C<$server> one of the servers defined in the koha-conf.xml file @@ -786,8 +827,7 @@ creates one, and connects to the database. This database handle is cached for future use: if you call Cdbh> twice, you will get the same handle both -times. If you need a second database handle, use C<&new_dbh> and -possibly C<&set_dbh>. +times. If you need a second database handle, use C<&new_dbh>. =cut @@ -826,64 +866,6 @@ sub new_dbh return &dbh({ new => 1 }); } -=head2 set_dbh - - $my_dbh = C4::Connect->new_dbh; - C4::Connect->set_dbh($my_dbh); - ... - C4::Connect->restore_dbh; - -C<&set_dbh> and C<&restore_dbh> work in a manner analogous to -C<&set_context> and C<&restore_context>. - -C<&set_dbh> saves the current database handle on a stack, then sets -the current database handle to C<$my_dbh>. - -C<$my_dbh> is assumed to be a good database handle. - -=cut - -#' -sub set_dbh -{ - my $self = shift; - my $new_dbh = shift; - - # Save the current database handle on the handle stack. - # We assume that $new_dbh is all good: if the caller wants to - # screw himself by passing an invalid handle, that's fine by - # us. - push @{$context->{"dbh_stack"}}, $context->{"dbh"}; - $context->{"dbh"} = $new_dbh; -} - -=head2 restore_dbh - - C4::Context->restore_dbh; - -Restores the database handle saved by an earlier call to -Cset_dbh>. - -=cut - -#' -sub restore_dbh -{ - my $self = shift; - - if ($#{$context->{"dbh_stack"}} < 0) - { - # Stack underflow - die "DBH stack underflow"; - } - - # Pop the old database handle and set it. - $context->{"dbh"} = pop @{$context->{"dbh_stack"}}; - - # FIXME - If it is determined that restore_context should - # return something, then this function should, too. -} - =head2 queryparser $queryparser = C4::Context->queryparser diff --git a/Koha/Cache.pm b/Koha/Cache.pm index 6b41e3c..a37bfa0 100644 --- a/Koha/Cache.pm +++ b/Koha/Cache.pm @@ -272,7 +272,7 @@ sub set_in_cache { $value = dclone( $value ) if ref($value) and not $unsafe; # Set in L1 cache; exit if we are caching an undef - $L1_cache{ $key } = $value; + $L1_cache{ $self->{namespace} }{ $key } = $value; return if !defined $value; # We consider an expiry of 0 to be infinite @@ -324,12 +324,12 @@ sub get_from_cache { return unless ( $self->{$cache} && ref( $self->{$cache} ) =~ m/^Cache::/ ); # Return L1 cache value if exists - if ( exists $L1_cache{$key} ) { + if ( exists $L1_cache{ $self->{namespace} }{ $key } ) { # No need to deep copy if it's a scalar # Or if we do not need to deep copy - return $L1_cache{$key} - if not ref $L1_cache{$key} or $unsafe; - return dclone $L1_cache{$key}; + return $L1_cache{ $self->{namespace} }{ $key } + if not ref $L1_cache{ $self->{namespace} }{ $key } or $unsafe; + return dclone $L1_cache{ $self->{namespace} }{ $key }; } my $get_sub = $self->{ref($self->{$cache}) . "_get"}; @@ -337,9 +337,9 @@ sub get_from_cache { # Update the L1 cache when fetching the L2 cache # Otherwise the L1 cache won't ever be populated - $L1_cache{$key} = $value; + $L1_cache{ $self->{namespace} }{ $key } = $value; - $value = dclone $value if ref $L1_cache{$key} and not $unsafe; + $value = dclone $value if ref $L1_cache{ $self->{namespace} }{ $key } and not $unsafe; return $value; } @@ -360,7 +360,7 @@ sub clear_from_cache { return unless ( $self->{$cache} && ref( $self->{$cache} ) =~ m/^Cache::/ ); # Clear from L1 cache - delete $L1_cache{$key}; + delete $L1_cache{ $self->{namespace} }{ $key }; return $self->{$cache}->delete($key) if ( ref( $self->{$cache} ) =~ m'^Cache::Memcached' ); @@ -389,7 +389,7 @@ sub flush_all { sub flush_L1_cache { my( $self ) = @_; - %L1_cache = (); + delete $L1_cache{ $self->{namespace} }; } =head1 TIED INTERFACE diff --git a/Koha/Database.pm b/Koha/Database.pm index d40eb52..959c00d 100644 --- a/Koha/Database.pm +++ b/Koha/Database.pm @@ -47,10 +47,9 @@ __PACKAGE__->mk_accessors(qw( )); # database connection from the data given in the current context, and # returns it. sub _new_schema { + my $context = shift || C4::Context->current(); - my $context = C4::Context->new(); - - my $db_driver = $context->{db_driver}; + my $db_driver = $context->db_driver; my $db_name = $context->config("database"); my $db_host = $context->config("hostname"); @@ -122,16 +121,16 @@ sub schema { return $database->{schema} if defined $database->{schema}; } - $database->{schema} = &_new_schema(); + $database->{schema} = &_new_schema($params->{context}); return $database->{schema}; } =head2 new_schema - $schema = $database->new_schema; + $schema = $database->new_schema($context); -Creates a new connection to the Koha database for the current context, -and returns the database handle (a C object). +Creates a new connection to the Koha database for the context +(current is default), and returns the database handle (a C object). The handle is not saved anywhere: this method is strictly a convenience function; the point is that it knows which database to @@ -143,7 +142,7 @@ connect to so that the caller doesn't have to know. sub new_schema { my $self = shift; - return &_new_schema(); + return &_new_schema(@_); } =head2 set_schema @@ -200,6 +199,29 @@ sub restore_schema { # return something, then this function should, too. } +=head2 run_with_schema + + $database->run_with_schema( $schema, sub {...} ); + +Restores the database handle saved by an earlier call to +C<$database-Eset_schema> C<$database-Erestore_schema> wrapper. + +=cut + +sub run_with_schema { + my $self = shift; + my $schema = shift or croak "No schema"; + my $code = shift or croak "No sub"; + + $self->set_schema; + local $@; + my $ret = eval { $code->(@_) }; + my $died = $@; + $self->restore_schema; + die $died if $died; + return $ret; +} + =head2 EXPORT None by default. diff --git a/Koha/Handler/Plack.pm b/Koha/Handler/Plack.pm new file mode 100644 index 0000000..af3f6cb --- /dev/null +++ b/Koha/Handler/Plack.pm @@ -0,0 +1,163 @@ +package Koha::Handler::Plack; + +# Copyright (c) 2016 Catalyst IT +# +# 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 2 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +=head1 NAME + + Koha::Handler::Plack - Plack helper + +=head1 SYNOPSIS + + koha.psgi: + use Koha::Handler::Plack; + + my %HOST_CONF = ( + 'koha1.com' => { ... }, + 'koha2.com' => { ... }, + ... + ); + # last line + Koha::Handler::Plack->app_per_host(\%HOST_CONF); + + See C below + +=head1 DESCRIPTION + + Some handy function to help with Koha/Plack in a multi-host situation. + + The problem: + Koha app relies on env vars. This should be changed, ie C4::Context should + be upgraded to Koha::App, but until then we need a gap filler. That's + because once up, there's no way to pass on new env to a psgi container. + In Apache, for instance, we can specify env vars per virtual host. Plack + has no such concept. + + Solution: + We need to modify the environment in situ, per virtual host - app_per_host(). + We specify env for each hostname, and apply. + +=cut + +use Modern::Perl; +use Carp; + +use Plack::App::URLMap; + +=head1 CLASS METHODS + +=head2 app_per_host($host_apps) + + App wrapper for per virtual host scenario. + + C<$host_apps>: + { + hostname => 'koha1.com', + app => $app1, + context => $context1, + }, + { + hostname => ['koha2.com', 'www.koha2.com'], + app => $app2, + context => $context2, + }, + ... + + C is mandatory. + + koha.psgi: + + use Plack::Builder; + use Plack::App::CGIBin; + + use C4::Context; + + my $opac_app = builder { + enable "Plack::Middleware::Static", + path => qr{^/opac-tmpl/}, root => '/usr/share/koha/opac/htdocs/'; + + enable 'StackTrace'; + mount "/cgi-bin/koha" => Plack::App::CGIBin->new(root => "/usr/share/koha/opac/cgi-bin/opac"); + }; + my $intranet_app = builder { + enable "Plack::Middleware::Static", + path => qr{^/intranet-tmpl/}, root => '/usr/share/koha/intranet/htdocs/'; + + enable 'StackTrace'; + mount "/cgi-bin/koha" => Plack::App::CGIBin->new(root => "/usr/share/koha/cgi-bin"); + }; + + my @host_def; + + my $conf_file_1 = "/etc/koha/site-1/koha_conf.xml"; + my $context_1 = C4::Context->new($conf_file_1); + push @host_def, + { + hostname => [ "public.host.for.site-1", "www.public.host.for.site-1" ], + app => $opac_app, + context => $context_1, + }, + { + hostname => "intranet.host.for.site-1", + app => $intranet_app, + context => $context_1, + }; + + my $conf_file_2 = "/etc/koha/site-1/koha_conf.xml"; + my $context_2 = C4::Context->new($conf_file_2); + push @host_def, + { + hostname => "public.host.for.site-2", + app => $opac_app, + context => $context_2, + }, + { + hostname => "intranet.host.for.site-2", + app => $intranet_app, + context => $context_2, + }; + + ... + + Koha::Handler::Plack->app_per_host( \@host_def ); + +=cut + +sub app_per_host { + my $class = shift; + my $sites = shift or die "No sites spec"; + + my $map = Plack::App::URLMap->new; + foreach my $site_params ( @$sites ) { + my $hosts = $site_params->{hostname} or croak "No hostname"; + $hosts = [$hosts] unless ref $hosts; + + my $app = $site_params->{app} or croak "No app"; + my $context = $site_params->{context} or croak "No Koha Context"; + + foreach my $host (@$hosts) { + $map->map("http://$host/" => sub { + my $env = shift; + + return $context->run_within_context(sub { $app->($env) }); + }); + } + } + return $map->to_app; +} + +1; diff --git a/Koha/Handler/Plack/CGI.pm b/Koha/Handler/Plack/CGI.pm new file mode 100644 index 0000000..36c6907 --- /dev/null +++ b/Koha/Handler/Plack/CGI.pm @@ -0,0 +1,228 @@ +package Koha::Handler::Plack::CGI; + +# Copyright (c) 2016 Catalyst IT +# +# 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 2 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +=head1 NAME + + Koha::Handler::Plack::CGI - Plack helper for CGI scripts + +=head1 SYNOPSIS + + koha.psgi: + use Koha::Handler::Plack::CGI; + + my %koha_env = ( + opac => { + static_root => '/usr/share/koha/opac/htdocs', + script_root => '/usr/share/koha/opac', + }, + intranet => { + static_root => '/usr/share/koha/intranet/htdocs', + script_root => '/usr/share/koha/intranet' + } + ); + my @sites = ( + { + opac_hostname => 'koha1-opac.com', + intranet_hostname => 'koha1-intranet.com', + config = '/etc/koha/koha1/koha-conf.xml' + }, + { + opac_hostname => ['opac.koha2.com', 'www.opackoha2.com'], + intranet_hostname => ['intranet.koha2.com', 'www.intranetkoha2.com'], + config = '/etc/koha/koha2/koha-conf.xml' + }, + ); + + # last line + Koha::Handler::Plack::CGI->app_per_host(\%HOST_CONF); + + See C below + +=head1 DESCRIPTION + + CGI script runner. + + One beautiful day wiwill move away from that and have proper App module + with router and handlers + + See C + +=cut + +use Modern::Perl; +use Carp; + +use Plack::Builder; +use Plack::App::CGIBin; + +use parent "Koha::Handler::Plack"; + +use C4::Context; + +=head1 CLASS METHODS + +=head2 app($context, $env) + + Plack app builder fora CGI app + + C<$context>: "opac" or "intranet" + C<$env>: + { + static_root => '...', + script_root => '...', + pugins => [ + [ 'StackTrace' ], + ... + ], + } + + koha.psgi: + + Koha::Handler::Plack::CGI->app( "opac", \%opac_app_env ); + +=cut + +sub app { + my $class = shift; + my $context = shift; + croak "Invalid app context '$context' - must be 'opac' or 'intranet'" + unless $context =~ m/^(opac|intranet)$/; + my $env = shift or croak "No $context env details"; + + my $static_root = $env->{static_root} or croak "No $context static_root"; + $static_root = "$static_root/" unless $static_root =~ m!/$!; + my $script_root = $env->{script_root} or croak "No $context script_root"; + $script_root =~ s!/$!!; + my $plugins = $env->{plugins} || []; + my $is_intranet = $context eq "intranet"; + + builder { + enable "Plack::Middleware::Static", + path => qr{^/$context-tmpl/}, root => $static_root; + + map enable(@$_), @$plugins; + + mount "/cgi-bin/koha" => Plack::App::CGIBin->new(root => $script_root)->to_app; + mount "/" => sub { + return [ 302, [ Location => '/cgi-bin/koha/' . ( $is_intranet ? 'mainpage.pl' : 'opac-main.pl' ) ], [] ]; + }; + }; +} + +=head2 multi_site($env, $sites) + + App wrapper for per virtual host scenario. + + C<$env>: + { + opac => { + static_root => '/usr/share/koha/opac/htdocs', + script_root => '/usr/share/koha/opac/cgi-bin/opac', + pugins => [ + [ 'StackTrace' ], + ], + }, + intranet => { + static_root => '/usr/share/koha/intranet/htdocs', + script_root => '/usr/share/koha/cgi-bin' + } + } + C<$sites>: + { + namespace => 'koha1', + opac_hostname => 'koha1-opac.com', + intranet_hostname => 'koha1-intranet.com', + config => '/etc/koha/sites/koha1/koha-conf.xml', + shared_config => 1 + }, + { + namespace => 'koha2', + opac_hostname => ['opac.koha2.com', 'www.opackoha2.com'], + intranet_hostname => ['intranet.koha2.com', 'www.intranetkoha2.com'], + config => '/etc/koha/sites/koha2/koha-conf.xml' + }, + ... + + koha.psgi: + + Koha::Handler::Plack::CGI->multi_site( \%koha_app_env, \@sites ); + +=cut + +my $DUMMY_KOHA_CONF = "DUMMY"; +sub multi_site { + my $class = shift; + my $env = shift or croak "No Koha env details"; + my $sites = shift or croak "No sites spec"; + + my ($opac_app, $intranet_app); + + if (my $opac = $env->{opac}) { + $opac_app = $class->app('opac', $opac); + } + + if (my $intranet = $env->{intranet}) { + $intranet_app = $class->app('intranet', $intranet); + } + + my @host_def = map { + my $namespace = $_->{namespace} or croak "No namespace"; + my $config = $_->{config} or croak "Site without config"; + my $shared_context = $_->{shared_context}; + + my $context = C4::Context->new($config, $namespace); + + my @hd; + if (my $hostname = $_->{opac_hostname}) { + croak "You have OPAC hosts without OPAC env details" unless $opac_app; + push @hd, { + hostname => $hostname, + app => sub { + # XXX this may need some rethinking + local $ENV{KOHA_CONF} = \$DUMMY_KOHA_CONF; + local $ENV{MEMCACHED_NAMESPACE} = $namespace; + + $opac_app->(@_); + }, + context => $context, + shared_context => $shared_context, + }; + } + if (my $hostname = $_->{intranet_hostname}) { + croak "You have Intranet hosts without Intranet env details" unless $intranet_app; + push @hd, { + hostname => $hostname, + app => sub { + # XXX this may need some rethinking + local $ENV{KOHA_CONF} = \$DUMMY_KOHA_CONF; + local $ENV{MEMCACHED_NAMESPACE} = $namespace; + + $intranet_app->(@_); + }, + context => $context, + shared_context => $shared_context, + }; + } + @hd; + } @$sites; + + return $class->app_per_host( \@host_def ); +} + +1; diff --git a/about.pl b/about.pl index ca8ff9f..59bcd9b 100755 --- a/about.pl +++ b/about.pl @@ -101,7 +101,7 @@ my $warnIsRootUser = (! $loggedinuser); my $warnNoActiveCurrency = (! defined Koha::Acquisition::Currencies->get_active); my @xml_config_warnings; -my $context = new C4::Context; +my $context = C4::Context->current; if ( ! defined C4::Context->config('zebra_bib_index_mode') ) { push @xml_config_warnings, { diff --git a/admin/systempreferences.pl b/admin/systempreferences.pl index 67e0638..861508f 100755 --- a/admin/systempreferences.pl +++ b/admin/systempreferences.pl @@ -387,7 +387,7 @@ output_html_with_http_headers $input, $cookie, $template->output; # .pref files. sub get_prefs_from_files { - my $context = C4::Context->new(); + my $context = C4::Context->current(); my $path_pref_en = $context->config('intrahtdocs') . '/prog/en/modules/admin/preferences'; # Get all .pref file names diff --git a/misc/cronjobs/check-url.pl b/misc/cronjobs/check-url.pl index 71885ab..2869446 100755 --- a/misc/cronjobs/check-url.pl +++ b/misc/cronjobs/check-url.pl @@ -190,7 +190,7 @@ sub check_all_url { my $checker = C4::URL::Checker->new($timeout,$agent); $checker->{ host_default } = $host; - my $context = new C4::Context( ); + my $context = C4::Context->current(); my $dbh = $context->dbh; my $sth = $dbh->prepare( "SELECT biblionumber FROM biblioitems WHERE url <> ''" ); diff --git a/misc/plack/koha-multi.psgi b/misc/plack/koha-multi.psgi new file mode 100644 index 0000000..e897f02 --- /dev/null +++ b/misc/plack/koha-multi.psgi @@ -0,0 +1,29 @@ +#!/usr/bin/perl + +# This is a minimal example. You can include all frills from koha.psgi +# To try it: +# plackup -I /usr/share/koha/lib --port 5010 koha-multi.psgi + +my %KOHA_ENV = ( + opac => { + static_root => '/usr/share/koha/opac/htdocs', + script_root => '/usr/share/koha/opac/cgi-bin/opac', + pugins => [ + # don't enable this plugin in production, since stack traces reveal too much information + # about system to potential attackers! + [ 'StackTrace' ], + ], + }, + intranet => { + static_root => '/usr/share/koha/intranet/htdocs', + script_root => '/usr/share/koha/intranet/cgi-bin', + } +); +my @SITES = map { + namespace => $_, + opac_hostname => "opac.$_.my-koha-multisite.net", + intranet_hostname => "intranet.$_.my-koha-multisite.net", + config => "/etc/koha/sites/$_/koha-conf.xml" +}, qw(koha1 koha2 koha3); + +Koha::Handler::Plack::CGI->multi_site( \%KOHA_ENV, \@SITES ); diff --git a/misc/translator/LangInstaller.pm b/misc/translator/LangInstaller.pm index 683897d..14a21c7 100644 --- a/misc/translator/LangInstaller.pm +++ b/misc/translator/LangInstaller.pm @@ -56,7 +56,7 @@ sub new { my $self = { }; - my $context = C4::Context->new(); + my $context = C4::Context->current(); $self->{context} = $context; $self->{path_pref_en} = $context->config('intrahtdocs') . '/prog/en/modules/admin/preferences'; @@ -140,7 +140,7 @@ sub new { sub po_filename { my $self = shift; - my $context = C4::Context->new; + my $context = C4::Context->current(); my $trans_path = $Bin . '/po'; my $trans_file = "$trans_path/" . $self->{lang} . "-pref.po"; return $trans_file; diff --git a/t/Koha_Handler_Plack.t b/t/Koha_Handler_Plack.t new file mode 100644 index 0000000..8172940 --- /dev/null +++ b/t/Koha_Handler_Plack.t @@ -0,0 +1,136 @@ +#!/usr/bin/perl + +use Test::More tests => 15; +use Plack::Test; +use Plack::Test::MockHTTP; +use Test::Mock::LWP::Dispatch; +use Test::MockModule; +use HTTP::Request::Common; +use FindBin qw($Bin); +use Data::Dumper; + +use_ok("Koha::Handler::Plack"); +use_ok("Koha::Handler::Plack::CGI"); + +use C4::Context; + +my $db = Test::MockModule->new('Koha::Database'); +$db->mock( + _new_schema => sub { + return $_[0]; + } +); + +sub make_response { + return join ";", map defined($_) ? $_ : "", @_; +} +sub dummy_val { + return C4::Context->config("dummy"); +} +sub check_context { + my $dummy_val = dummy_val(); + is $dummy_val, undef, "context preserved" + or diag("dummy val: $dummy_val"); +} + +my $app = sub { + return [ + 200, + [ 'Content-Type' => 'text/plain' ], + [ make_response(dummy_val()) ] + ]; +}; +my $generic_url = "http://dummyhost.com/"; + +my $KOHA_CONF_XML = < + + test + XML + . + + +EOS + +my @HOST_CONF = ( + { + hostname => ['koha-file.com', 'www.koha-file.com'], + app => $app, + context => C4::Context->new("$Bin/conf/koha1/koha-conf.xml"), + _dummy => "KOHA1" + }, + { + hostname => ['koha-xml.com', 'www.koha-xml.com'], + app => $app, + context => C4::Context->new(\$KOHA_CONF_XML), + _dummy => "XML" + }, +); +test_psgi + app => Koha::Handler::Plack->app_per_host(\@HOST_CONF), + client => sub { + my $cb = shift; + + foreach my $site_params ( @HOST_CONF ) { + my $valid_response = make_response( + $site_params->{_dummy} + ); + foreach (@{$site_params->{hostname}}) { + my $res = $cb->(GET "http://$_/"); + is $res->content, $valid_response, $_ + or diag(Dumper($site_params, $_, $res->as_string)); + check_context(); + } + } + + $res = $cb->(GET $generic_url); + is $res->code, 404, "app_per_host unknown host" + or diag($res->as_string); + }; + +my %MULTI_HOST_ENV = ( + opac => { + static_root => "$Bin/../koha-tmpl/opac-tmpl/bootstrap", + script_root => "$Bin/../opac", + }, + intranet => { + static_root => "$Bin/../koha-tmpl/intranet-tmpl/bootstrap", + script_root => "$Bin/.." + } +); +my @MULTI_HOST_SITES = ( + { + namespace => 'koha1', + opac_hostname => ['opac.koha1.com', 'www.opac.koha1.com'], + intranet_hostname => ['intranet.koha1.com', 'www.intranet.koha1.com'], + config => "$Bin/conf/koha1/koha-conf.xml", + }, + { + namespace => 'koha2', + opac_hostname => ['opac.koha2.com', 'www.opac.koha2.com'], + intranet_hostname => ['intranet.koha2.com', 'www.intranet.koha2.com'], + config => "$Bin/conf/koha2/koha-conf.xml", + shared_context => 1, + }, +); +test_psgi + app => Koha::Handler::Plack::CGI->multi_site(\%MULTI_HOST_ENV, \@MULTI_HOST_SITES), + client => sub { + my $cb = shift; + + foreach my $site (@MULTI_HOST_SITES) { + my $opac = $site->{opac_hostname}; + foreach my $host (@$opac) { +# this is not really a test, but cannot do any better atm +# TODO: a complex test involving two database connections + my $res = $cb->(GET "http://$host/"); + # A future implementation may not redirect + if ($res->is_redirect) { + my $loc = $res->header("Location"); + $res = $cb->(GET "http://$host$loc"); + } + is $res->code, 500, "multi_site() $host" + or diag($res->as_string); + } + } + }; diff --git a/t/conf/dummy/koha-conf.xml b/t/conf/dummy/koha-conf.xml new file mode 100644 index 0000000..d4c96b0 --- /dev/null +++ b/t/conf/dummy/koha-conf.xml @@ -0,0 +1,7 @@ + + + dummy + DUMMY + . + + diff --git a/t/conf/koha1/koha-conf.xml b/t/conf/koha1/koha-conf.xml new file mode 100644 index 0000000..371d039 --- /dev/null +++ b/t/conf/koha1/koha-conf.xml @@ -0,0 +1,7 @@ + + + koha1 + KOHA1 + . + + diff --git a/t/conf/koha2/koha-conf.xml b/t/conf/koha2/koha-conf.xml new file mode 100644 index 0000000..437e772 --- /dev/null +++ b/t/conf/koha2/koha-conf.xml @@ -0,0 +1,5 @@ + + + KOHA2 + + diff --git a/t/db_dependent/Amazon.t b/t/db_dependent/Amazon.t index 2304073..a5b316f 100755 --- a/t/db_dependent/Amazon.t +++ b/t/db_dependent/Amazon.t @@ -14,7 +14,7 @@ BEGIN { use_ok('C4::External::Amazon'); } -my $context = C4::Context->new(); +my $context = C4::Context->current(); my $locale = $context->preference('AmazonLocale'); diff --git a/t/db_dependent/Context.t b/t/db_dependent/Context.t index b5a050f..c3f6066 100755 --- a/t/db_dependent/Context.t +++ b/t/db_dependent/Context.t @@ -47,7 +47,7 @@ C4::Context->clear_syspref_cache(); C4::Context->enable_syspref_cache(); $dbh->rollback; -ok($koha = C4::Context->new, 'C4::Context->new'); +ok($koha = C4::Context->current, 'C4::Context->current'); my @keys = keys %$koha; my $width = 0; if (ok(@keys)) { diff --git a/t/db_dependent/Template/Plugin/KohaDates.t b/t/db_dependent/Template/Plugin/KohaDates.t index fe18836..2088347 100644 --- a/t/db_dependent/Template/Plugin/KohaDates.t +++ b/t/db_dependent/Template/Plugin/KohaDates.t @@ -14,7 +14,7 @@ BEGIN { my $module_context = new Test::MockModule('C4::Context'); my $date = "1973-05-21"; -my $context = C4::Context->new(); +my $context = C4::Context->current(); my $filter = Koha::Template::Plugin::KohaDates->new(); ok ($filter, "new()"); diff --git a/t/db_dependent/XISBN.t b/t/db_dependent/XISBN.t index 2f6d63b..45e01dd 100755 --- a/t/db_dependent/XISBN.t +++ b/t/db_dependent/XISBN.t @@ -26,7 +26,7 @@ my $search_module = new Test::MockModule('C4::Search'); $search_module->mock('SimpleSearch', \&Mock_SimpleSearch ); -my $context = C4::Context->new; +my $context = C4::Context->current; my ( $biblionumber_tag, $biblionumber_subfield ) = GetMarcFromKohaField( 'biblio.biblionumber', '' ); diff --git a/t/db_dependent/sysprefs.t b/t/db_dependent/sysprefs.t index 340e89a..07552f1 100755 --- a/t/db_dependent/sysprefs.t +++ b/t/db_dependent/sysprefs.t @@ -19,7 +19,7 @@ # along with Koha; if not, see . use Modern::Perl; -use Test::More tests => 8; +use Test::More tests => 11; use C4::Context; # Start transaction @@ -60,4 +60,15 @@ is(C4::Context->preference('testpreference'), 'def', 'caching preferences'); C4::Context->clear_syspref_cache(); is(C4::Context->preference('testpreference'), undef, 'clearing preference cache'); +delete $ENV{OVERRIDE_SYSPREF_opacheader}; + +my $DUMMY_KOHA_CONF = "DUMMY"; +my $context1 = C4::Context->new($DUMMY_KOHA_CONF, "context1"); +is( $context1->preference('opacheader'), $opacheader, 'context1 "opacheader"'); + +my $context2 = C4::Context->new($DUMMY_KOHA_CONF, "context2"); +$context2->set_preference( 'opacheader', $newopacheader ); +is( $context1->preference('opacheader'), $opacheader, 'context1 "opacheader"'); +is( $context2->preference('opacheader'), $newopacheader, 'context2 "opacheader"'); + $dbh->rollback; -- 2.7.4 From srdjan at catalyst.net.nz Wed Jun 1 06:33:25 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Wed, 1 Jun 2016 16:33:25 +1200 Subject: [Koha-patches] [PATCH] bug_15562: Removed Koha::Cache->get_instance() Message-ID: <1464755605-9137-1-git-send-email-srdjan@catalyst.net.nz> There should be no cache singleton, full stop. If Koha is to move away from .pl scripts that is. As an interim measure Koha::Cache->get_instance() is replaced with C4::Context->cache, in the vein of C4::Context->memcached. In that respect it will continue to work in the singleton-ish way if context is used as a singleton, but supports cache-per-context. Koha::Handler::Plack->app_per_host() cache sysprefs using Context memcached. https://bugs.koha-community.org/show_bug.cgi?id=15562 --- C4/Biblio.pm | 4 +- C4/Calendar.pm | 15 ++-- C4/Context.pm | 123 ++++++++++++++++++++------------ C4/External/OverDrive.pm | 6 +- C4/Koha.pm | 3 +- C4/Utils/DataTables/ColumnsSettings.pm | 3 +- Koha/Cache.pm | 17 ----- Koha/Calendar.pm | 5 +- Koha/Handler/Plack.pm | 41 ++++++++++- Koha/Handler/Plack/CGI.pm | 2 +- Koha/Template/Plugin/Cache.pm | 3 +- admin/biblio_framework.pl | 3 +- admin/koha2marclinks.pl | 2 +- admin/marc_subfields_structure.pl | 2 +- admin/marctagstructure.pl | 5 +- opac/svc/report | 5 +- svc/report | 4 +- t/Cache.t | 4 +- t/Calendar.t | 4 +- t/Context.t | 28 +++++++- t/Koha_Template_Plugin_Cache.t | 4 +- t/db_dependent/Context.t | 8 +-- t/db_dependent/Filter_MARC_ViewPolicy.t | 2 +- tools/newHolidays.pl | 4 +- 24 files changed, 180 insertions(+), 117 deletions(-) diff --git a/C4/Biblio.pm b/C4/Biblio.pm index ae1f2f3..2395459 100644 --- a/C4/Biblio.pm +++ b/C4/Biblio.pm @@ -38,8 +38,8 @@ use C4::Charset; use C4::Linker; use C4::OAI::Sets; use C4::Debug; +use C4::Context; -use Koha::Cache; use Koha::Authority::Types; use Koha::Acquisition::Currencies; use Koha::SearchEngine; @@ -1122,7 +1122,7 @@ sub GetMarcStructure { $frameworkcode = "" unless $frameworkcode; $forlibrarian = $forlibrarian ? 1 : 0; - my $cache = Koha::Cache->get_instance(); + my $cache = C4::Context->cache; my $cache_key = "MarcStructure-$forlibrarian-$frameworkcode"; my $cached = $cache->get_from_cache($cache_key); return $cached if $cached; diff --git a/C4/Calendar.pm b/C4/Calendar.pm index 82dc35a..3a38173 100644 --- a/C4/Calendar.pm +++ b/C4/Calendar.pm @@ -23,7 +23,6 @@ use Carp; use Date::Calc qw( Date_to_Days Today); use C4::Context; -use Koha::Cache; use constant ISO_DATE_FORMAT => "%04d-%02d-%02d"; @@ -276,7 +275,7 @@ sub insert_single_holiday { # changed the 'single_holidays' table, lets force/reset its cache - my $cache = Koha::Cache->get_instance(); + my $cache = C4::Context->cache; $cache->clear_from_cache( 'single_holidays') ; $cache->clear_from_cache( 'exception_holidays') ; @@ -321,7 +320,7 @@ sub insert_exception_holiday { $self->{'exception_holidays'}->{"$options{year}/$options{month}/$options{day}"}{description} = $options{description}; # changed the 'single_holidays' table, lets force/reset its cache - my $cache = Koha::Cache->get_instance(); + my $cache = C4::Context->cache; $cache->clear_from_cache( 'single_holidays') ; $cache->clear_from_cache( 'exception_holidays') ; @@ -422,7 +421,7 @@ UPDATE special_holidays SET title = ?, description = ? $self->{'single_holidays'}->{"$options{year}/$options{month}/$options{day}"}{description} = $options{description}; # changed the 'single_holidays' table, lets force/reset its cache - my $cache = Koha::Cache->get_instance(); + my $cache = C4::Context->cache; $cache->clear_from_cache( 'single_holidays') ; $cache->clear_from_cache( 'exception_holidays') ; @@ -465,7 +464,7 @@ UPDATE special_holidays SET title = ?, description = ? $self->{'exception_holidays'}->{"$options{year}/$options{month}/$options{day}"}{description} = $options{description}; # changed the 'single_holidays' table, lets force/reset its cache - my $cache = Koha::Cache->get_instance(); + my $cache = C4::Context->cache; $cache->clear_from_cache( 'single_holidays') ; $cache->clear_from_cache( 'exception_holidays') ; @@ -546,7 +545,7 @@ sub delete_holiday { } # changed the 'single_holidays' table, lets force/reset its cache - my $cache = Koha::Cache->get_instance(); + my $cache = C4::Context->cache; $cache->clear_from_cache( 'single_holidays') ; $cache->clear_from_cache( 'exception_holidays') ; @@ -577,7 +576,7 @@ sub delete_holiday_range { $sth->execute($self->{branchcode}, $options{day}, $options{month}, $options{year}); # changed the 'single_holidays' table, lets force/reset its cache - my $cache = Koha::Cache->get_instance(); + my $cache = C4::Context->cache; $cache->clear_from_cache( 'single_holidays') ; $cache->clear_from_cache( 'exception_holidays') ; @@ -631,7 +630,7 @@ sub delete_exception_holiday_range { $sth->execute($self->{branchcode}, $options{day}, $options{month}, $options{year}); # changed the 'single_holidays' table, lets force/reset its cache - my $cache = Koha::Cache->get_instance(); + my $cache = C4::Context->cache; $cache->clear_from_cache( 'single_holidays') ; $cache->clear_from_cache( 'exception_holidays') ; } diff --git a/C4/Context.pm b/C4/Context.pm index 63a71d6..51e370f 100644 --- a/C4/Context.pm +++ b/C4/Context.pm @@ -18,7 +18,7 @@ package C4::Context; use strict; use warnings; -use vars qw($AUTOLOAD $context @context_stack $servers $memcached $ismemcached); +use vars qw($AUTOLOAD $context @context_stack $memcached_servers); BEGIN { if ($ENV{'HTTP_USER_AGENT'}) { require CGI::Carp; @@ -88,20 +88,9 @@ BEGIN { } # else there is no browser to send fatals to! # Check if there are memcached servers set - $servers = $ENV{'MEMCACHED_SERVERS'}; - if ($servers) { - # Load required libraries and create the memcached object - require Cache::Memcached; - $memcached = Cache::Memcached->new({ - servers => [ $servers ], - debug => 0, - compress_threshold => 10_000, - expire_time => 600, - namespace => $ENV{'MEMCACHED_NAMESPACE'} || 'koha' - }); - # Verify memcached available (set a variable and test the output) - $ismemcached = $memcached->set('ismemcached','1'); - } + $memcached_servers = $ENV{'MEMCACHED_SERVERS'}; + # Load required libraries and create the memcached object + require Cache::Memcached if $memcached_servers; } @@ -219,29 +208,57 @@ sub current { return $context; } -=head2 ismemcached +sub _new_memcached { + my $namespace = shift or die "No memcached namespace"; + + return unless $memcached_servers; + return Cache::Memcached->new({ + servers => [ $memcached_servers ], + debug => 0, + compress_threshold => 10_000, + expire_time => 600, + namespace => $namespace || $ENV{'MEMCACHED_NAMESPACE'} || 'koha' + }); +} +# Verify memcached available (test the output) +sub _ping_memcached { + my $memcached = shift or croak "No memcached"; -Returns the value of the $ismemcached variable (0/1) + return $memcached->set('ismemcached','1'); +} + +=head2 cache + +Returns the cache object or undef =cut -sub ismemcached { - return $ismemcached; +sub cache { + my $self = shift; + $self = $context unless ref ($self); + + return $self->{cache}; } =head2 memcached -If $ismemcached is true, returns the $memcache variable. -Returns undef otherwise +Returns the memcached object or undef + +=head2 ismemcached =cut sub memcached { - if ($ismemcached) { - return $memcached; - } else { - return; - } + my $self = shift; + $self = $context unless ref ($self); + + my $memcached = $self->{memcached} or return; + return _ping_memcached($memcached) ? $memcached : undef; +} + +sub ismemcached { + my $self = shift; + return $self->memcached; } sub db_driver { @@ -285,10 +302,14 @@ sub import { # default context already exists? return if $context; - if ($ismemcached) { + return if $config_file && $config_file eq ":no_config"; + + my $memcached = _new_memcached($ENV{'MEMCACHED_NAMESPACE'} || 'koha'); + if ($memcached) { # retrieve from memcached - if (my $self = $memcached->get('kohaconf')) { - $context = $self; + if ($context = $memcached->get('kohaconf')) { + $context->{memcached} = $memcached; + $context->{cache} = Koha::Cache->new({namespace => $context->{namespace}}); return; } } @@ -315,16 +336,13 @@ sub import { } # no ? so load it! - return if $config_file && $config_file eq ":no_config"; - my $new_ctx = __PACKAGE__->new($config_file); - return unless $new_ctx; - - # if successfully loaded, use it by default - $context = $new_ctx; - - if ($ismemcached) { - $memcached->set('kohaconf',$new_ctx); + $context = $pkg->_new($config_file) or return; + if ( $memcached && _ping_memcached($memcached) ) { + $memcached->set('kohaconf',$context); + # Canot serialize cache objects + $context->{memcached} = $memcached; } + $context->{cache} = Koha::Cache->new({namespace => $context->{namespace}}); } use Scalar::Util qw(openhandle); @@ -366,6 +384,21 @@ sub new { my $conf_fname = shift or croak "No conf"; my $namespace = shift; + my $self = $class->_new($conf_fname, $namespace); + + if ($memcached_servers) { + $self->{memcached} = _new_memcached($namespace); + } + $self->{cache} = Koha::Cache->new({namespace => $namespace}); + + return $self; +} + +sub _new { + my $class = shift; + my $conf_fname = shift or croak "No conf"; + my $namespace = shift; + my $self = XMLin( $conf_fname, keyattr => ['id'], @@ -378,7 +411,6 @@ sub new { $self->{config_file} = $conf_fname; $self->{namespace} = $namespace; $self->{use_syspref_cache} = 1; - $self->{syspref_cache} = Koha::Cache->new({namespace => $namespace}); $self->{"Zconn"} = undef; # Zebra Connections $self->{"marcfromkohafield"} = undef; # the hash with relations between koha table fields and MARC field/subfield @@ -559,7 +591,7 @@ sub preference { if defined $ENV{"OVERRIDE_SYSPREF_$var"}; my $cached_var = $self->{use_syspref_cache} - ? $self->{syspref_cache}->get_from_cache("syspref_$var") + ? $self->cache->get_from_cache("syspref_$var") : undef; return $cached_var if defined $cached_var; @@ -568,7 +600,8 @@ sub preference { my $value = $syspref ? $syspref->value() : undef; if ( $self->{use_syspref_cache} ) { - $self->{syspref_cache}->set_in_cache("syspref_$var", $value); + $self->cache->set_in_cache("syspref_$var", $value); + $self->{sysprefs}{$var} = $value if $self; } return $value; } @@ -609,8 +642,8 @@ used with Plack and other persistent environments. sub disable_syspref_cache { my ($self) = @_; $self = $context unless ref $self; - $self->{use_syspref_cache} = 0; $self->clear_syspref_cache(); + $self->{use_syspref_cache} = 0; } =head2 clear_syspref_cache @@ -627,7 +660,7 @@ sub clear_syspref_cache { my ($self) = @_; $self = $context unless ref $self; return unless $self->{use_syspref_cache}; - $self->{syspref_cache}->flush_all; + $self->cache->flush_all; } =head2 set_preference @@ -680,7 +713,7 @@ sub set_preference { } if ( $self->{use_syspref_cache} ) { - $self->{syspref_cache}->set_in_cache( "syspref_$variable", $value ); + $self->cache->set_in_cache( "syspref_$variable", $value ); } return $syspref; @@ -702,7 +735,7 @@ sub delete_preference { if ( Koha::Config::SysPrefs->find( $var )->delete ) { if ( $self->{use_syspref_cache} ) { - $self->{syspref_cache}->clear_from_cache("syspref_$var"); + $self->cache->clear_from_cache("syspref_$var"); } return 1; diff --git a/C4/External/OverDrive.pm b/C4/External/OverDrive.pm index 12135c5..0e71707 100644 --- a/C4/External/OverDrive.pm +++ b/C4/External/OverDrive.pm @@ -22,7 +22,7 @@ use warnings; use Koha; use JSON; -use Koha::Cache; +use C4::Context; use HTTP::Request; use HTTP::Request::Common; use LWP::Authen::Basic; @@ -97,9 +97,7 @@ sub GetOverDriveToken { return unless ( $key && $secret ) ; - my $cache; - - eval { $cache = Koha::Cache->get_instance() }; + my $cache = C4::Context->cache; my $token; $cache and $token = $cache->get_from_cache( "overdrive_token" ) and return $token; diff --git a/C4/Koha.pm b/C4/Koha.pm index 7fe07f1..3a67e7f 100644 --- a/C4/Koha.pm +++ b/C4/Koha.pm @@ -25,7 +25,6 @@ use strict; use C4::Context; use C4::Branch; # Can be removed? -use Koha::Cache; use Koha::DateUtils qw(dt_from_string); use Koha::Libraries; use DateTime::Format::MySQL; @@ -1017,7 +1016,7 @@ sub GetAuthorisedValues { C4::Context->userenv ? C4::Context->userenv->{"branch"} : ""; my $cache_key = "AuthorisedValues-$category-$opac-$branch_limit"; - my $cache = Koha::Cache->get_instance(); + my $cache = C4::Context->cache; my $result = $cache->get_from_cache($cache_key); return $result if $result; diff --git a/C4/Utils/DataTables/ColumnsSettings.pm b/C4/Utils/DataTables/ColumnsSettings.pm index a107886..31068b4 100644 --- a/C4/Utils/DataTables/ColumnsSettings.pm +++ b/C4/Utils/DataTables/ColumnsSettings.pm @@ -5,11 +5,10 @@ use List::Util qw( first ); use YAML; use C4::Context; use Koha::Database; -use Koha::Cache; sub get_yaml { my $yml_path = C4::Context->config('intranetdir') . '/admin/columns_settings.yml'; - my $cache = Koha::Cache->get_instance(); + my $cache = C4::Context->cache; my $yaml = $cache->get_from_cache('ColumnsSettingsYaml'); unless ($yaml) { diff --git a/Koha/Cache.pm b/Koha/Cache.pm index a37bfa0..f133ff8 100644 --- a/Koha/Cache.pm +++ b/Koha/Cache.pm @@ -49,23 +49,6 @@ __PACKAGE__->mk_ro_accessors( our %L1_cache; -=head2 get_instance - - my $cache = Koha::Cache->get_instance(); - -This gets a shared instance of the cache, set up in a very default way. This is -the recommended way to fetch a cache object. If possible, it'll be -persistent across multiple instances. - -=cut - -our $singleton_cache; -sub get_instance { - my ($class) = @_; - $singleton_cache = $class->new() unless $singleton_cache; - return $singleton_cache; -} - =head2 new Create a new Koha::Cache object. This is required for all cache-related functionality. diff --git a/Koha/Calendar.pm b/Koha/Calendar.pm index 1321621..ada63ee 100644 --- a/Koha/Calendar.pm +++ b/Koha/Calendar.pm @@ -7,7 +7,6 @@ use DateTime; use DateTime::Set; use DateTime::Duration; use C4::Context; -use Koha::Cache; use Carp; sub new { @@ -55,7 +54,7 @@ sub _init { sub exception_holidays { my ( $self ) = @_; - my $cache = Koha::Cache->get_instance(); + my $cache = C4::Context->cache; my $cached = $cache->get_from_cache('exception_holidays'); return $cached if $cached; @@ -84,7 +83,7 @@ sub exception_holidays { sub single_holidays { my ( $self, $date ) = @_; my $branchcode = $self->{branchcode}; - my $cache = Koha::Cache->get_instance(); + my $cache = C4::Context->cache; my $single_holidays = $cache->get_from_cache('single_holidays'); # $single_holidays looks like: diff --git a/Koha/Handler/Plack.pm b/Koha/Handler/Plack.pm index af3f6cb..bce66ac 100644 --- a/Koha/Handler/Plack.pm +++ b/Koha/Handler/Plack.pm @@ -69,6 +69,7 @@ use Plack::App::URLMap; hostname => 'koha1.com', app => $app1, context => $context1, + shared_context => 1 }, { hostname => ['koha2.com', 'www.koha2.com'], @@ -78,13 +79,16 @@ use Plack::App::URLMap; ... C is mandatory. + If C is set to true, some Context properties will be preserved across + forked processes. Useful if both OPAC and Intranet apps are served here, so no restart + is needed when Context cached properties cnamge values. Needs memcached. koha.psgi: use Plack::Builder; use Plack::App::CGIBin; - use C4::Context; + use C4::Context ":no_config"; my $opac_app = builder { enable "Plack::Middleware::Static", @@ -137,6 +141,8 @@ use Plack::App::URLMap; =cut +# We cannot store whole Context object, may contain non-serializable things +my @CONTEXT_SHARED_PROPERTIES = qw(sysprefs); sub app_per_host { my $class = shift; my $sites = shift or die "No sites spec"; @@ -148,12 +154,43 @@ sub app_per_host { my $app = $site_params->{app} or croak "No app"; my $context = $site_params->{context} or croak "No Koha Context"; + my $shared_context = $site_params->{shared_context}; + my $cache = $context->memcached; + if ($shared_context) { + if ($cache) { + foreach (@CONTEXT_SHARED_PROPERTIES) { + # Clean slate + $cache->delete($_); + } + } + else { + warn "shared_context works only with memcached"; + } + } foreach my $host (@$hosts) { $map->map("http://$host/" => sub { my $env = shift; - return $context->run_within_context(sub { $app->($env) }); + # may have stopped meanwhile or whatever + my $cache = $context->memcached; + if ($shared_context && $cache) { + foreach (@CONTEXT_SHARED_PROPERTIES) { + if (my $shared = $cache->get($_)) { + $context->{$_} = $shared; + } + } + } + + my $ret = $context->run_within_context(sub { $app->($env) }); + + if ($shared_context && $cache) { + foreach (@CONTEXT_SHARED_PROPERTIES) { + $cache->set($_, $context->{$_}); + } + } + + $ret; }); } } diff --git a/Koha/Handler/Plack/CGI.pm b/Koha/Handler/Plack/CGI.pm index 36c6907..9892562 100644 --- a/Koha/Handler/Plack/CGI.pm +++ b/Koha/Handler/Plack/CGI.pm @@ -73,7 +73,7 @@ use Plack::App::CGIBin; use parent "Koha::Handler::Plack"; -use C4::Context; +use C4::Context ":no_config"; =head1 CLASS METHODS diff --git a/Koha/Template/Plugin/Cache.pm b/Koha/Template/Plugin/Cache.pm index dbb1c82..085f977 100644 --- a/Koha/Template/Plugin/Cache.pm +++ b/Koha/Template/Plugin/Cache.pm @@ -34,8 +34,7 @@ sub new { $cache = delete $params->{cache}; } else { - require Koha::Cache; - $cache = Koha::Cache->get_instance(); + $cache = $context->cache; } my $self = bless { CACHE => $cache, diff --git a/admin/biblio_framework.pl b/admin/biblio_framework.pl index 79a0db1..79f7060 100755 --- a/admin/biblio_framework.pl +++ b/admin/biblio_framework.pl @@ -26,12 +26,11 @@ use C4::Output; use Koha::Biblios; use Koha::BiblioFramework; use Koha::BiblioFrameworks; -use Koha::Cache; my $input = new CGI; my $frameworkcode = $input->param('frameworkcode') || q||; my $op = $input->param('op') || q|list|; -my $cache = Koha::Cache->get_instance(); +my $cache = C4::Context->cache; my @messages; my ( $template, $borrowernumber, $cookie ) = get_template_and_user( diff --git a/admin/koha2marclinks.pl b/admin/koha2marclinks.pl index 9ccca37..68f1e55 100755 --- a/admin/koha2marclinks.pl +++ b/admin/koha2marclinks.pl @@ -59,7 +59,7 @@ else { } my $dbh = C4::Context->dbh; -my $cache = Koha::Cache->get_instance(); +my $cache = C4::Context->cache; ################## ADD_FORM ################################## # called by default. Used to create form to add or modify a record diff --git a/admin/marc_subfields_structure.pl b/admin/marc_subfields_structure.pl index 22d4398..46b749c 100755 --- a/admin/marc_subfields_structure.pl +++ b/admin/marc_subfields_structure.pl @@ -77,7 +77,7 @@ my ( $template, $borrowernumber, $cookie ) = get_template_and_user( debug => 1, } ); -my $cache = Koha::Cache->get_instance(); +my $cache = C4::Context->cache; my $op = $input->param('op') || ""; $tagfield =~ s/\,//g; diff --git a/admin/marctagstructure.pl b/admin/marctagstructure.pl index 7728687..26406f4 100755 --- a/admin/marctagstructure.pl +++ b/admin/marctagstructure.pl @@ -25,9 +25,6 @@ use C4::Auth; use C4::Koha; use C4::Context; use C4::Output; -use C4::Context; - -use Koha::Cache; # retrieve parameters my $input = new CGI; @@ -46,7 +43,7 @@ my $pagesize = 20; my $script_name = "/cgi-bin/koha/admin/marctagstructure.pl"; my $dbh = C4::Context->dbh; -my $cache = Koha::Cache->get_instance(); +my $cache = C4::Context->cache; # open template my ($template, $loggedinuser, $cookie) diff --git a/opac/svc/report b/opac/svc/report index bfc84e5..98d2aeb 100755 --- a/opac/svc/report +++ b/opac/svc/report @@ -23,12 +23,11 @@ use Modern::Perl; +use C4::Context; use C4::Reports::Guided; use JSON; use CGI qw ( -utf8 ); -use Koha::Cache; - my $query = CGI->new(); my $report_id = $query->param('id'); my $report_name = $query->param('name'); @@ -41,7 +40,7 @@ die "Sorry this report is not public\n" unless $report_rec->{public}; my @sql_params = $query->param('sql_params'); -my $cache = Koha::Cache->get_instance(); +my $cache = C4::Context->cache; my $cache_active = $cache->is_cache_active; my ($cache_key, $json_text); if ($cache_active) { diff --git a/svc/report b/svc/report index da1b9b3..d380090 100755 --- a/svc/report +++ b/svc/report @@ -25,7 +25,7 @@ use C4::Reports::Guided; use JSON; use CGI qw ( -utf8 ); -use Koha::Cache; +use C4::Context; my $query = CGI->new(); @@ -48,7 +48,7 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user( } ); -my $cache = Koha::Cache->get_instance(); +my $cache = C4::Context->cache; my $cache_active = $cache->is_cache_active; my ($cache_key, $json_text); if ($cache_active) { diff --git a/t/Cache.t b/t/Cache.t index 101f723..35dea11 100644 --- a/t/Cache.t +++ b/t/Cache.t @@ -32,7 +32,7 @@ SKIP: { # Set a special namespace for testing, to avoid breaking # if test is run with a different user than Apache's. $ENV{ MEMCACHED_NAMESPACE } = 'unit_tests'; - my $cache = Koha::Cache->get_instance(); + my $cache = C4::Context->cache; skip "Cache not enabled", 33 unless ( $cache->is_cache_active() && defined $cache ); @@ -224,7 +224,7 @@ SKIP: { END { SKIP: { $ENV{ MEMCACHED_NAMESPACE } = 'unit_tests'; - my $cache = Koha::Cache->get_instance(); + my $cache = C4::Context->cache; skip "Cache not enabled", 1 unless ( $cache->is_cache_active() ); is( $destructorcount, 1, 'Destructor run exactly once' ); diff --git a/t/Calendar.t b/t/Calendar.t index 4d48c02..55f5d89 100755 --- a/t/Calendar.t +++ b/t/Calendar.t @@ -22,7 +22,7 @@ use Test::MockModule; use DateTime; use DateTime::Duration; -use Koha::Cache; +use C4::Context; use Koha::DateUtils; use Module::Load::Conditional qw/check_install/; @@ -89,7 +89,7 @@ fixtures_ok [ ], ], "add fixtures"; -my $cache = Koha::Cache->get_instance(); +my $cache = C4::Context->cache; $cache->clear_from_cache( 'single_holidays') ; # 'MPL' branch is arbitrary, is not used at all but is needed for initialization diff --git a/t/Context.t b/t/Context.t index e2c1825..d737509 100755 --- a/t/Context.t +++ b/t/Context.t @@ -2,7 +2,7 @@ use Modern::Perl; use DBI; -use Test::More tests => 26; +use Test::More tests => 29; use Test::MockModule; BEGIN { @@ -62,3 +62,29 @@ is(C4::Context->interface, 'opac', 'interface still opac'); #Bug 14751 is( C4::Context->interface( 'SiP' ), 'sip', 'interface SiP' ); is( C4::Context->interface( 'COMMANDLINE' ), 'commandline', 'interface commandline uc' ); + +my $DUMMY_KOHA_CONF = "TEST"; +my $ctx_a = C4::Context->new($DUMMY_KOHA_CONF, "a"); +my $ctx_b = C4::Context->new($DUMMY_KOHA_CONF, "b"); +my $cache_key = "test_C4::Context"; + +SKIP: { + skip "No cache", 3 unless $ctx_a->cache->is_cache_active && $ctx_b->cache->is_cache_active; + + # Light warm up + C4::Context->cache->set_in_cache($cache_key, 'c'); + $ctx_a->cache->set_in_cache($cache_key, 'a'); + $ctx_b->cache->set_in_cache($cache_key, 'b'); + is(C4::Context->cache->get_from_cache($cache_key), 'c', "Correct default cache value"); + is($ctx_a->cache->get_from_cache($cache_key), 'a', "Correct cache 'a' value"); + is($ctx_b->cache->get_from_cache($cache_key), 'b', "Correct cache 'b' value"); + + # A bit more extravagant + # Cannot run atm, fails due to no database in config +# $ctx_a->run_within_context( sub { +# $ctx_b->cache->set_in_cache($cache_key, 'bb'); +# C4::Context->cache->set_in_cache($cache_key, 'aa'); +# } ); +# is($ctx_a->cache->get_from_cache($cache_key), 'aa', "Correct cache 'a' value"); +# is($ctx_b->cache->get_from_cache($cache_key), 'bb', "Correct cache 'b' value"); +} diff --git a/t/Koha_Template_Plugin_Cache.t b/t/Koha_Template_Plugin_Cache.t index da20f61..15ee048 100644 --- a/t/Koha_Template_Plugin_Cache.t +++ b/t/Koha_Template_Plugin_Cache.t @@ -1,6 +1,8 @@ use Modern::Perl; use Test::More tests => 2; +use C4::Context; + use_ok('Koha::Template::Plugin::Cache'); -ok(my $cache = Koha::Template::Plugin::Cache->new()); +ok(my $cache = Koha::Template::Plugin::Cache->new(C4::Context->current)); diff --git a/t/db_dependent/Context.t b/t/db_dependent/Context.t index c3f6066..b35f83d 100755 --- a/t/db_dependent/Context.t +++ b/t/db_dependent/Context.t @@ -12,14 +12,8 @@ use Koha::Database; BEGIN { $debug = $ENV{DEBUG} || 0; - - # Note: The overall number of tests may vary by configuration. - # First we need to check your environmental variables - for (qw(KOHA_CONF PERL5LIB)) { - ok( $ret = $ENV{$_}, "ENV{$_} = $ret" ); - } - use_ok('C4::Context'); } +use_ok('C4::Context'); ok($dbh = C4::Context->dbh(), 'Getting dbh from C4::Context'); diff --git a/t/db_dependent/Filter_MARC_ViewPolicy.t b/t/db_dependent/Filter_MARC_ViewPolicy.t index ba446bc..a0123ec 100644 --- a/t/db_dependent/Filter_MARC_ViewPolicy.t +++ b/t/db_dependent/Filter_MARC_ViewPolicy.t @@ -71,7 +71,7 @@ sub run_hiding_tests { $sth->execute($hidden_value); - my $cache = Koha::Cache->get_instance(); + my $cache = Koha::Cache->new(); $cache->flush_all(); # easy way to ensure DB is queried again. my $processor = Koha::RecordProcessor->new( diff --git a/tools/newHolidays.pl b/tools/newHolidays.pl index eda4c1b..38f290c 100755 --- a/tools/newHolidays.pl +++ b/tools/newHolidays.pl @@ -10,7 +10,7 @@ use CGI qw ( -utf8 ); use C4::Auth; use C4::Output; -use Koha::Cache; +use C4::Context; use C4::Calendar; use DateTime; @@ -129,6 +129,6 @@ sub add_holiday { } } # we updated the single_holidays table, so wipe its cache - my $cache = Koha::Cache->get_instance(); + my $cache = C4::Context->cache; $cache->clear_from_cache( 'single_holidays') ; } -- 2.7.4 From sjohnson at hpplnj.org Wed Jun 1 06:34:33 2016 From: sjohnson at hpplnj.org (sjohnson at hpplnj.org) Date: Wed, 1 Jun 2016 00:34:33 -0400 Subject: [Koha-patches] Out of office Message-ID: I will be out of the library May 18, 2016 - June 6, 2016. I will periodically check my email and either get back to you or forward your email to a colleague to answer your query. If you have an urgent need please call the library at 732-572-2750. Thank you, Sherry Johnson Coordinator of Adult Services Highland Park Public Library www.hpplnj.org 732-572-2750 -------------- next part -------------- An HTML attachment was scrubbed... URL: From srdjan at catalyst.net.nz Thu Jun 2 02:58:46 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Thu, 2 Jun 2016 12:58:46 +1200 Subject: [Koha-patches] [PATCH] Bug 16620: Translatability: Fix problem with isolated word "please" in auth.tt Message-ID: <1464829126-9952-1-git-send-email-srdjan@catalyst.net.nz> From: Marc V?ron This patch fixes a translatability problem (syntax in different languages) with a tag-isolated word "please" in koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt To test: - Verify in code that there is no sentence spliting by a-tags (lines 80/84). Signed-off-by: Srdjan --- koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt index 8887812..411c563 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt @@ -76,13 +76,12 @@

Sorry, the CAS login failed.

[% END %] -

If you have a CAS account, [% IF ( casServerUrl ) %] - please click here to login.

+

If you have a CAS account, please click here to login.

[% END %] [% IF ( casServersLoop ) %] -please choose against which one you would like to authenticate:

+

If you have a CAS account, please choose against which one you would like to authenticate:

    [% FOREACH casServer IN casServersLoop %]
  • [% casServer.name %]
  • -- 2.7.4 From sjohnson at hpplnj.org Thu Jun 2 12:00:35 2016 From: sjohnson at hpplnj.org (sjohnson at hpplnj.org) Date: Thu, 2 Jun 2016 06:00:35 -0400 Subject: [Koha-patches] Out of office Message-ID: <545a55776af94bb6b972375b4226846c@586f37742f0349fc82c63a195888d554> I will be out of the library May 18, 2016 - June 6, 2016. I will periodically check my email and either get back to you or forward your email to a colleague to answer your query. If you have an urgent need please call the library at 732-572-2750. Thank you, Sherry Johnson Coordinator of Adult Services Highland Park Public Library www.hpplnj.org 732-572-2750 -------------- next part -------------- An HTML attachment was scrubbed... URL: From sjohnson at hpplnj.org Fri Jun 3 12:00:43 2016 From: sjohnson at hpplnj.org (sjohnson at hpplnj.org) Date: Fri, 3 Jun 2016 06:00:43 -0400 Subject: [Koha-patches] Out of office Message-ID: I will be out of the library May 18, 2016 - June 6, 2016. I will periodically check my email and either get back to you or forward your email to a colleague to answer your query. If you have an urgent need please call the library at 732-572-2750. Thank you, Sherry Johnson Coordinator of Adult Services Highland Park Public Library www.hpplnj.org 732-572-2750 -------------- next part -------------- An HTML attachment was scrubbed... URL: From sjohnson at hpplnj.org Sat Jun 4 12:00:55 2016 From: sjohnson at hpplnj.org (sjohnson at hpplnj.org) Date: Sat, 4 Jun 2016 06:00:55 -0400 Subject: [Koha-patches] Out of office Message-ID: <1e0954b9f803471f801fd32e5805eff6@c0cf5eb761984c3880faca4a12ec0956> I will be out of the library May 18, 2016 - June 6, 2016. I will periodically check my email and either get back to you or forward your email to a colleague to answer your query. If you have an urgent need please call the library at 732-572-2750. Thank you, Sherry Johnson Coordinator of Adult Services Highland Park Public Library www.hpplnj.org 732-572-2750 -------------- next part -------------- An HTML attachment was scrubbed... URL: From sjohnson at hpplnj.org Sun Jun 5 12:00:36 2016 From: sjohnson at hpplnj.org (sjohnson at hpplnj.org) Date: Sun, 5 Jun 2016 06:00:36 -0400 Subject: [Koha-patches] Out of office Message-ID: I will be out of the library May 18, 2016 - June 6, 2016. I will periodically check my email and either get back to you or forward your email to a colleague to answer your query. If you have an urgent need please call the library at 732-572-2750. Thank you, Sherry Johnson Coordinator of Adult Services Highland Park Public Library www.hpplnj.org 732-572-2750 -------------- next part -------------- An HTML attachment was scrubbed... URL: From srdjan at catalyst.net.nz Mon Jun 6 06:35:11 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Mon, 6 Jun 2016 16:35:11 +1200 Subject: [Koha-patches] [PATCH] Bug 16668 - Move t/Ris.t to t/db_dependent/Ris.t Message-ID: <1465187711-4936-1-git-send-email-srdjan@catalyst.net.nz> From: Mirko Tietgen Move test to db_dependent Signed-off-by: Srdjan --- t/{ => db_dependent}/Ris.t | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename t/{ => db_dependent}/Ris.t (100%) diff --git a/t/Ris.t b/t/db_dependent/Ris.t similarity index 100% rename from t/Ris.t rename to t/db_dependent/Ris.t -- 2.7.4 From srdjan at catalyst.net.nz Mon Jun 6 07:10:04 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Mon, 6 Jun 2016 17:10:04 +1200 Subject: [Koha-patches] [PATCH] Bug 16618: 00-load.t prematurely stops all testing Message-ID: <1465189804-16274-1-git-send-email-srdjan@catalyst.net.nz> From: Mark Tompsett Rather than add/remove regular expressions to skip modules (like bug 9054), encapsulate the decision logic into a separate function. Currently there are three libraries which trigger halts: Koha::NorwegianDB (which was already there) Koha::ElasticSearch::Indexer Koha::SearchEngine::Elasticsearch::Search TEST PLAN --------- 1) prove t/00-load.t -- should barf horribly on Catmandu stuff if not: sudo apt-get remove libcatmandu-marc-perl then repeat step. 2) apply patch 3) prove t/00-load.t -- should not barf horribly 4) run koha qa test tools NOTE: The four optional modules for Koha::NorwegianDB are listed in the PerlDependencies.pm, while there is no mention of Catmandu libraries at all there. This may be another bug which needs fixing. TECH NOTES (for ideas of how to tinker around): These three things should trigger the three module cases: sudo apt-get remove libcatmandu-marc-perl sudo apt-get remove libcatmandu-store-elasticsearch-perl sudo apt-get remove libconvert-basen-perl You probably had koha-perldeps installed before, so the following wil mostly fix: sudo apt-get install koha-perldeps libcatmandu-marc-perl And in case you didn't have elastic search stuff installed: echo deb http://packages.elastic.co/elasticsearch/1.7/debian stable main | sudo tee /etc/apt/sources.list.d/elasticsearch.list wget -O- https://packages.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add - sudo apt-get update cd ~ wget http://debian.koha-community.org/koha/otherthings/elasticsearch_deps.tar.gz tar xvf elasticsearch_deps.tar.gz cd es_deps sudo dpkg i lib* sudo apt-get install -f Signed-off-by: Srdjan --- t/00-load.t | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/t/00-load.t b/t/00-load.t index 21b62eb..ab4b08f 100644 --- a/t/00-load.t +++ b/t/00-load.t @@ -2,6 +2,8 @@ # This file is part of Koha. # +# Copyright (c) 2016 Mark Tompsett -- is_testable() +# # 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 @@ -20,7 +22,7 @@ use Modern::Perl; use Test::More; use File::Spec; use File::Find; - +use English qw( -no_match_vars ); use t::lib::Mocks; =head1 DESCRIPTION @@ -59,13 +61,48 @@ find( return unless $m =~ s/[.]pm$//; $m =~ s{^.*/Koha/}{Koha/}; $m =~ s{/}{::}g; - return if $m =~ /Koha::NorwegianPatronDB/; # uses non-mandatory modules - use_ok($m) || BAIL_OUT("***** PROBLEMS LOADING FILE '$m'"); + if ( is_testable($m) ) { + use_ok($m) || BAIL_OUT("***** PROBLEMS LOADING FILE '$m'"); + } }, }, $lib ); +# Optional modules are causing checks to fail +# This checks for the particular modules to determine +# if the testing is possible or not. +# +# Returns 1 if possible, 0 if not. +sub is_testable { + my ($module_name) = @_; + my @needed_module_names; + my $return_value = 1; + if ( $module_name =~ /Koha::NorwegianPatronDB/xsm ) { + @needed_module_names = + ( 'SOAP::Lite', 'Crypt::GCrypt', 'Digest::SHA', 'Convert::BaseN' ); + } + elsif ( $module_name =~ /Koha::ElasticSearch::Indexer/xsm ) { + @needed_module_names = + ( 'Catmandu::Importer::MARC', 'Catmandu::Store::ElasticSearch' ); + } + elsif ( $module_name =~ /Koha::SearchEngine::Elasticsearch::Search/xsm ) { + @needed_module_names = ( 'Catmandu::Store::ElasticSearch' ); + } + foreach my $current_name (@needed_module_names) { + my $relative_pathname = $current_name; + $relative_pathname =~ s/::/\//gxsm; + $relative_pathname .= '.pm'; + my $check_result = eval { require "$relative_pathname"; 1; }; + if ($EVAL_ERROR) { + diag( +"Skipping testing of $module_name, because $current_name is not installed." + ); + $return_value = 0; + } + } + return $return_value; +} done_testing(); -- 2.7.4 From srdjan at catalyst.net.nz Mon Jun 6 07:14:48 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Mon, 6 Jun 2016 17:14:48 +1200 Subject: [Koha-patches] [PATCH] Bug 16667: Unused variable and function call in circulation.pl Message-ID: <1465190088-17996-1-git-send-email-srdjan@catalyst.net.nz> From: Tomas Cohen Arazi This patch removes an unused occurence of the $branches variable. Probably a leftover from a recent rewrite. To test: - Run: $ git grep '$branches' circ/circulation.pl => FAIL: Only on occurence of the variable - Apply the patch - Run: $ git grep '$branches' circ/circulation.pl => SUCCESS: The variable has been removed - Sign off :-D Regards Signed-off-by: Srdjan --- circ/circulation.pl | 2 -- 1 file changed, 2 deletions(-) diff --git a/circ/circulation.pl b/circ/circulation.pl index b2bcdd1..b2201cf 100755 --- a/circ/circulation.pl +++ b/circ/circulation.pl @@ -125,8 +125,6 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user ( } ); -my $branches = GetBranches(); - my $force_allow_issue = $query->param('forceallow') || 0; if (!C4::Auth::haspermission( C4::Context->userenv->{id} , { circulate => 'force_checkout' } )) { $force_allow_issue = 0; -- 2.7.4 From srdjan at catalyst.net.nz Mon Jun 6 07:21:36 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Mon, 6 Jun 2016 17:21:36 +1200 Subject: [Koha-patches] [PATCH] Bug 16649: Make OpenLibrarySearch test pass even if launches offline Message-ID: <1465190496-20376-1-git-send-email-srdjan@catalyst.net.nz> From: Jonathan Druart Test plan: prove t/OpenLibrarySearch.t should return green even if you are offline Signed-off-by: Srdjan --- t/OpenLibrarySearch.t | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/t/OpenLibrarySearch.t b/t/OpenLibrarySearch.t index 8084453..b0865e6 100644 --- a/t/OpenLibrarySearch.t +++ b/t/OpenLibrarySearch.t @@ -22,7 +22,11 @@ use Test::More tests => 1; use LWP::Simple; use JSON; my $content = get("https://openlibrary.org/search.json?q=9780201038095"); -my $data = from_json($content); -my $numFound = $data->{numFound}; -ok( $numFound > 0, "The openlibrary ws should return at least 1 result" ); +SKIP: { + skip "json has not been retrieved from openlibrary.org", 1 unless defined $content; + my $data = from_json($content); + my $numFound = $data->{numFound}; + + ok( $numFound > 0, "The openlibrary ws should return at least 1 result" ); +} -- 2.7.4 From srdjan at catalyst.net.nz Mon Jun 6 07:28:02 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Mon, 6 Jun 2016 17:28:02 +1200 Subject: [Koha-patches] [PATCH] Bug 16636: t/00-load.t warning from C4/External/BakerTaylor.pm Message-ID: <1465190882-22788-1-git-send-email-srdjan@catalyst.net.nz> From: Mark Tompsett Since the tests are expecting an initialize function, the initialize call was just moved outside of the INIT block. TEST PLAN --------- 1) prove t/00-load.t -- warnings about INIT for hbyymmincr 2) prove `git grep -l BakerTaylor | grep [.]t$` -- should all run okay 3) apply patch 4) repeat steps 1 and 2 -- warning should be gone, and everything else run okay 5) run koha qa test tools Signed-off-by: Srdjan --- C4/External/BakerTaylor.pm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/C4/External/BakerTaylor.pm b/C4/External/BakerTaylor.pm index 4450e9b..3f52a57 100644 --- a/C4/External/BakerTaylor.pm +++ b/C4/External/BakerTaylor.pm @@ -29,6 +29,7 @@ use warnings; use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION); use vars qw($user $pass $agent $image_url $link_url); +&initialize; BEGIN { require Exporter; @@ -37,9 +38,6 @@ BEGIN { @EXPORT_OK = qw(&availability &content_cafe &image_url &link_url &http_jacket_link); %EXPORT_TAGS = (all=>\@EXPORT_OK); } -INIT { - &initialize; -} sub initialize { $user = (@_ ? shift : C4::Context->preference('BakerTaylorUsername') ) || ''; # LL17984 -- 2.7.4 From srdjan at catalyst.net.nz Mon Jun 6 07:33:15 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Mon, 6 Jun 2016 17:33:15 +1200 Subject: [Koha-patches] [PATCH] Bug 16635: t/00-load.t warning from C4/Barcodes/hbyymmincr.pm Message-ID: <1465191195-24705-1-git-send-email-srdjan@catalyst.net.nz> From: Mark Tompsett According to http://perldoc.perl.org/vars.html, "our" should be a reasonable substitute for the "use vars". By declaring as "our", and removing the INIT, prove t/00-load will no longer generate a warning about INIT for the C4/Barcodes/hbyymmincr.pm module. TEST PLAN --------- 1) prove t/00-load.t -- warnings about INIT for hbyymmincr 2) prove `git grep -l hbyymmincr | grep [.]t$` -- should all run okay 3) apply patch 4) repeat steps 1 and 2 -- warning should be gone, and everything else run okay 5) run koha qa test tools Signed-off-by: Srdjan --- C4/Barcodes/hbyymmincr.pm | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/C4/Barcodes/hbyymmincr.pm b/C4/Barcodes/hbyymmincr.pm index f963e9a..4e76012 100644 --- a/C4/Barcodes/hbyymmincr.pm +++ b/C4/Barcodes/hbyymmincr.pm @@ -29,16 +29,13 @@ use Koha::DateUtils qw( dt_from_string output_pref ); use vars qw(@ISA); use vars qw($debug $cgi_debug); # from C4::Debug, of course -use vars qw($branch $width); +our $branch = ''; +our $width = 4; # FIXME: 4 is too small for sizeable or multi-branch libraries. BEGIN { @ISA = qw(C4::Barcodes); } -INIT { - $branch = ''; - $width = 4; # FIXME: 4 is too small for sizeable or multi-branch libraries. -} # Generates barcode where hb = home branch Code, yymm = year/month catalogued, incr = incremental number, # increment resets yearly -fbcit -- 2.7.4 From sjohnson at hpplnj.org Mon Jun 6 12:01:58 2016 From: sjohnson at hpplnj.org (sjohnson at hpplnj.org) Date: Mon, 6 Jun 2016 06:01:58 -0400 Subject: [Koha-patches] Out of office Message-ID: <84752623834f4fbabae64391530ca540@d4b89c43b54f424d8f86c4148d441502> I will be out of the library May 18, 2016 - June 6, 2016. I will periodically check my email and either get back to you or forward your email to a colleague to answer your query. If you have an urgent need please call the library at 732-572-2750. Thank you, Sherry Johnson Coordinator of Adult Services Highland Park Public Library www.hpplnj.org 732-572-2750 -------------- next part -------------- An HTML attachment was scrubbed... URL: From srdjan at catalyst.net.nz Tue Jun 7 07:19:22 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Tue, 7 Jun 2016 17:19:22 +1200 Subject: [Koha-patches] [PATCH] Bug 13807 Rework main input loop in SIPServer Message-ID: <1465276762-25854-1-git-send-email-srdjan@catalyst.net.nz> From: Colin Campbell Debugging various problems in SIPServer and control of it, found it could loop on unread buffers (e.g. the LF of a CRLF if it was only expecting CR) making it unresponsive to signals. Reworked the input loop with an eye to removing unnecessary whiles and replacing the while(1) by a while( connection valid) Enhanced the timeout code by wapping in an eval. Moved the logic from SIP_read_packet into the server itself Hopefully this makes the already baroque code easier to navigate and it did seem the server was the logical place for this Removed no longer iused SIP_read_packet from Sip.pm Signed-off-by: Srdjan --- C4/SIP/SIPServer.pm | 107 +++++++++++++++++++++++++++++++++++----------------- C4/SIP/Sip.pm | 56 +-------------------------- 2 files changed, 74 insertions(+), 89 deletions(-) diff --git a/C4/SIP/SIPServer.pm b/C4/SIP/SIPServer.pm index 8722ab6..d556845 100755 --- a/C4/SIP/SIPServer.pm +++ b/C4/SIP/SIPServer.pm @@ -15,7 +15,6 @@ use C4::SIP::Sip::Constants qw(:all); use C4::SIP::Sip::Configuration; use C4::SIP::Sip::Checksum qw(checksum verify_cksum); use C4::SIP::Sip::MsgType qw( handle login_core ); -use C4::SIP::Sip qw( read_SIP_packet ); use base qw(Net::Server::PreFork); @@ -116,6 +115,7 @@ sub process_request { } else { &$transport($self); } + return; } # @@ -130,7 +130,7 @@ sub raw_transport { while (!$self->{account}) { local $SIG{ALRM} = sub { die "raw_transport Timed Out!\n"; }; syslog("LOG_DEBUG", "raw_transport: timeout is %d", $service->{timeout}); - $input = read_SIP_packet(*STDIN); + $input = read_request(); if (!$input) { # EOF on the socket syslog("LOG_INFO", "raw_transport: shutting down: EOF during login"); @@ -146,6 +146,7 @@ sub raw_transport { $self->sip_protocol_loop(); syslog("LOG_INFO", "raw_transport: shutting down"); + return; } sub get_clean_string { @@ -230,6 +231,7 @@ sub telnet_transport { syslog("LOG_DEBUG", "telnet_transport: uname/inst: '%s/%s'", $account->{id}, $account->{institution}); $self->sip_protocol_loop(); syslog("LOG_INFO", "telnet_transport: shutting down"); + return; } # @@ -242,7 +244,6 @@ sub sip_protocol_loop { my $service = $self->{service}; my $config = $self->{config}; my $timeout = $self->{service}->{timeout} || $config->{timeout} || 30; - my $input; # The spec says the first message will be: # SIP v1: SC_STATUS @@ -257,39 +258,77 @@ sub sip_protocol_loop { # case, the LOGIN message has already been processed (above). # # In short, we'll take any valid message here. - #my $expect = SC_STATUS; - local $SIG{ALRM} = sub { die "SIP Timed Out!\n"; }; - my $expect = ''; - while (1) { - alarm $timeout; - $input = read_SIP_packet(*STDIN); - unless ($input) { - return; # EOF + eval { + local $SIG{ALRM} = sub { + syslog( 'LOG_DEBUG', 'Inactive: timed out' ); + die "Timed Out!\n"; + }; + my $previous_alarm = alarm($timeout); + + while ( my $inputbuf = read_request() ) { + if ( !defined $inputbuf ) { + return; #EOF + } + alarm($timeout); + + unless ($inputbuf) { + syslog( "LOG_ERR", "sip_protocol_loop: empty input skipped" ); + print("96$CR"); + next; + } + + my $status = C4::SIP::Sip::MsgType::handle( $inputbuf, $self, q{} ); + if ( !$status ) { + syslog( + "LOG_ERR", + "sip_protocol_loop: failed to handle %s", + substr( $inputbuf, 0, 2 ) + ); + } + next if $status eq REQUEST_ACS_RESEND; } - # begin input hacks ... a cheap stand in for better Telnet layer - $input =~ s/^[^A-z0-9]+//s; # Kill leading bad characters... like Telnet handshakers - $input =~ s/[^A-z0-9]+$//s; # Same on the end, should get DOSsy ^M line-endings too. - while (chomp($input)) {warn "Extra line ending on input";} - unless ($input) { - syslog("LOG_ERR", "sip_protocol_loop: empty input skipped"); - print("96$CR"); - next; - } - # end cheap input hacks - my $status = handle($input, $self, $expect); - if (!$status) { - syslog("LOG_ERR", "sip_protocol_loop: failed to handle %s",substr($input,0,2)); - } - next if $status eq REQUEST_ACS_RESEND; - if ($expect && ($status ne $expect)) { - # We received a non-"RESEND" that wasn't what we were expecting. - syslog("LOG_ERR", "sip_protocol_loop: expected %s, received %s, exiting", $expect, $input); - } - # We successfully received and processed what we were expecting - $expect = ''; - alarm 0; - } + alarm($previous_alarm); + return; + }; + if ( $@ =~ m/timed out/i ) { + return; + } + return; } +sub read_request { + my $raw_length; + local $/ = "\015"; + + # proper SPEC: (octal) \015 = (hex) x0D = (dec) 13 = (ascii) carriage return + my $buffer = ; + if ( defined $buffer ) { + STDIN->flush(); # clear an extra linefeed + chomp $buffer; + $raw_length = length $buffer; + $buffer =~ s/^\s*[^A-z0-9]+//s; +# Every line must start with a "real" character. Not whitespace, control chars, etc. + $buffer =~ s/[^A-z0-9]+$//s; + +# Same for the end. Note this catches the problem some clients have sending empty fields at the end, like ||| + $buffer =~ s/\015?\012//g; # Extra line breaks must die + $buffer =~ s/\015?\012//s; # Extra line breaks must die + $buffer =~ s/\015*\012*$//s; + + # treat as one line to include the extra linebreaks we are trying to remove! + } + else { + syslog( 'LOG_DEBUG', 'EOF returned on read' ); + return; + } + my $len = length $buffer; + if ( $len != $raw_length ) { + my $trim = $raw_length - $len; + syslog( 'LOG_DEBUG', "read_request trimmed $trim character(s) " ); + } + + syslog( 'LOG_INFO', "INPUT MSG: '$buffer'" ); + return $buffer; +} 1; __END__ diff --git a/C4/SIP/Sip.pm b/C4/SIP/Sip.pm index a6cf97f..52eda1f 100644 --- a/C4/SIP/Sip.pm +++ b/C4/SIP/Sip.pm @@ -22,14 +22,13 @@ BEGIN { @ISA = qw(Exporter); @EXPORT_OK = qw(y_or_n timestamp add_field maybe_add add_count - denied sipbool boolspace write_msg read_SIP_packet + denied sipbool boolspace write_msg $error_detection $protocol_version $field_delimiter $last_response); %EXPORT_TAGS = ( all => [qw(y_or_n timestamp add_field maybe_add add_count denied sipbool boolspace write_msg - read_SIP_packet $error_detection $protocol_version $field_delimiter $last_response)]); } @@ -154,59 +153,6 @@ sub boolspace { return $bool ? 'Y' : ' '; } - -# read_SIP_packet($file) -# -# Read a packet from $file, using the correct record separator -# -sub read_SIP_packet { - my $record; - my $fh = shift or syslog("LOG_ERR", "read_SIP_packet: no filehandle argument!"); - my $len1 = 999; - - # local $/ = "\r"; # don't need any of these here. use whatever the prevailing $/ is. - local $/ = "\015"; # proper SPEC: (octal) \015 = (hex) x0D = (dec) 13 = (ascii) carriage return - { # adapted from http://perldoc.perl.org/5.8.8/functions/readline.html - undef $!; - $record = readline($fh); - if ( defined($record) ) { - while ( chomp($record) ) { 1; } - $len1 = length($record); - syslog( "LOG_DEBUG", "read_SIP_packet, INPUT MSG: '$record'" ); - $record =~ s/^\s*[^A-z0-9]+//s; # Every line must start with a "real" character. Not whitespace, control chars, etc. - $record =~ s/[^A-z0-9]+$//s; # Same for the end. Note this catches the problem some clients have sending empty fields at the end, like ||| - $record =~ s/\015?\012//g; # Extra line breaks must die - $record =~ s/\015?\012//s; # Extra line breaks must die - $record =~ s/\015*\012*$//s; # treat as one line to include the extra linebreaks we are trying to remove! - while ( chomp($record) ) { 1; } - - $record and last; # success - } - } - if ($record) { - my $len2 = length($record); - syslog("LOG_INFO", "read_SIP_packet, INPUT MSG: '$record'") if $record; - ($len1 != $len2) and syslog("LOG_DEBUG", "read_SIP_packet, trimmed %s character(s) (after chomps).", $len1-$len2); - } else { - syslog("LOG_WARNING", "read_SIP_packet input %s, end of input.", (defined($record) ? "empty ($record)" : 'undefined')); - } - # - # Cen-Tec self-check terminals transmit '\r\n' line terminators. - # This is actually very hard to deal with in perl in a reasonable - # since every OTHER piece of hardware out there gets the protocol - # right. - # - # The incorrect line terminator presents as a \r at the end of the - # first record, and then a \n at the BEGINNING of the next record. - # So, the simplest thing to do is just throw away a leading newline - # on the input. - # - # This is now handled by the vigorous cleansing above. - # syslog("LOG_INFO", encode_utf8("INPUT MSG: '$record'")) if $record; - syslog("LOG_INFO", "INPUT MSG: '$record'") if $record; - return $record; -} - # # write_msg($msg, $file) # -- 2.7.4 From srdjan at catalyst.net.nz Fri Jun 10 02:58:12 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Fri, 10 Jun 2016 12:58:12 +1200 Subject: [Koha-patches] [PATCH] Fix test data in issue.t and defaults for stats Message-ID: <1465520292-20966-1-git-send-email-srdjan@catalyst.net.nz> '' and 'Null' are not really NULL values https://bugs.koha-community.org/show_bug.cgi?id=14803 --- C4/Stats.pm | 14 +++++++------- t/db_dependent/Circulation/issue.t | 28 ++++++++++++++++------------ 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/C4/Stats.pm b/C4/Stats.pm index 54e3a39..bec439d 100644 --- a/C4/Stats.pm +++ b/C4/Stats.pm @@ -118,13 +118,13 @@ sub UpdateStats { # get the parameters my $branch = $params->{branch}; my $type = $params->{type}; - my $borrowernumber = exists $params->{borrowernumber} ? $params->{borrowernumber} :''; - my $itemnumber = exists $params->{itemnumber} ? $params->{itemnumber} :''; - my $amount = exists $params->{amount} ? $params->{amount} :''; - my $other = exists $params->{other} ? $params->{other} :''; - my $itemtype = exists $params->{itemtype} ? $params->{itemtype} :''; - my $accountno = exists $params->{accountno} ? $params->{accountno} :''; - my $ccode = exists $params->{ccode} ? $params->{ccode} :''; + my $borrowernumber = exists $params->{borrowernumber} ? $params->{borrowernumber} : undef; + my $itemnumber = exists $params->{itemnumber} ? $params->{itemnumber} : undef; + my $amount = exists $params->{amount} ? $params->{amount} : undef; + my $other = exists $params->{other} ? $params->{other} : undef; + my $itemtype = exists $params->{itemtype} ? $params->{itemtype} : undef; + my $accountno = exists $params->{accountno} ? $params->{accountno} : undef; + my $ccode = exists $params->{ccode} ? $params->{ccode} : undef; my $dbh = C4::Context->dbh; my $sth = $dbh->prepare( diff --git a/t/db_dependent/Circulation/issue.t b/t/db_dependent/Circulation/issue.t index a28b1c5..bbb7909 100644 --- a/t/db_dependent/Circulation/issue.t +++ b/t/db_dependent/Circulation/issue.t @@ -118,17 +118,17 @@ Koha::Library->new($samplebranch2)->store; my $samplecat = { categorycode => 'CAT1', description => 'Description1', - enrolmentperiod => 'Null', - enrolmentperioddate => 'Null', - dateofbirthrequired => 'Null', - finetype => 'Null', - bulk => 'Null', - enrolmentfee => 'Null', - overduenoticerequired => 'Null', - issuelimit => 'Null', - reservefee => 'Null', + enrolmentperiod => undef, + enrolmentperioddate => undef, + dateofbirthrequired => undef, + finetype => undef, + bulk => undef, + enrolmentfee => undef, + overduenoticerequired => undef, + issuelimit => undef, + reservefee => undef, hidelostitems => 0, - category_type => 'Null' + category_type => 'A', }; my $query = "INSERT INTO categories (categorycode,description,enrolmentperiod,enrolmentperioddate,dateofbirthrequired ,finetype,bulk,enrolmentfee,overduenoticerequired,issuelimit ,reservefee ,hidelostitems ,category_type) VALUES( ?,?,?,?,?,?,?,?,?,?,?,?,?)"; @@ -179,14 +179,18 @@ my $item_id2 = $sampleitem2[2]; #Add borrower my $borrower_id1 = C4::Members::AddMember( firstname => 'firstname1', - surname => 'surname1 ', + surname => 'surname1', + address => 'address 1', + city => 'city 1', categorycode => $samplecat->{categorycode}, branchcode => $samplebranch1->{branchcode}, ); my $borrower_1 = C4::Members::GetMember(borrowernumber => $borrower_id1); my $borrower_id2 = C4::Members::AddMember( firstname => 'firstname2', - surname => 'surname2 ', + surname => 'surname2', + address => 'address 2', + city => 'city 2', categorycode => $samplecat->{categorycode}, branchcode => $samplebranch2->{branchcode}, ); -- 2.7.4 From srdjan at catalyst.net.nz Fri Jun 10 02:58:26 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Fri, 10 Jun 2016 12:58:26 +1200 Subject: [Koha-patches] [PATCH] Test rental charges properly Message-ID: <1465520306-21100-1-git-send-email-srdjan@catalyst.net.nz> * AddIssuingCharge() test was always returning pass - removed and replaced with: * Test rental charges properly for both checkout and renewal https://bugs.koha-community.org/show_bug.cgi?id=14803 --- t/db_dependent/Circulation/issue.t | 49 ++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/t/db_dependent/Circulation/issue.t b/t/db_dependent/Circulation/issue.t index bbb7909..040b9ed 100644 --- a/t/db_dependent/Circulation/issue.t +++ b/t/db_dependent/Circulation/issue.t @@ -16,6 +16,7 @@ # along with Koha; if not, see . use Modern::Perl; +use Data::Dumper; use Koha::DateUtils; use DateTime::Duration; @@ -143,6 +144,15 @@ $dbh->do( $samplecat->{category_type} ); +my $TEST_ITEMTYPE = "_T_ITYPE"; +my %TEST_ITEMTYPE_REC = ( + itemtype => $TEST_ITEMTYPE, + rentalcharge => "1.50", +); +Koha::ItemType->new(\%TEST_ITEMTYPE_REC)->store; + +t::lib::Mocks::mock_preference( 'item-level_itypes', 1 ); + #Add biblio and item my $record = MARC::Record->new(); $record->append_fields( @@ -158,7 +168,8 @@ my @sampleitem1 = C4::Items::AddItem( homebranch => $samplebranch1->{branchcode}, holdingbranch => $samplebranch1->{branchcode}, issue => 1, - reserve => 1 + reserve => 1, + itype => $TEST_ITEMTYPE, }, $biblionumber ); @@ -170,7 +181,8 @@ my @sampleitem2 = C4::Items::AddItem( homebranch => $samplebranch2->{branchcode}, holdingbranch => $samplebranch2->{branchcode}, notforloan => 1, - issue => 1 + issue => 1, + itype => $TEST_ITEMTYPE, }, $biblionumber ); @@ -209,9 +221,16 @@ my $userenv = C4::Context->userenv #Begin Tests +my $bib = GetBiblioFromItemNumber( $item_id1); +$query = " SELECT count(*) FROM accountlines"; +my $sth = $dbh->prepare($query); +$sth->execute; +my $countaccount = $sth -> fetchrow_array; +is ($countaccount,0,"0 accountline exists"); + #Test AddIssue $query = " SELECT count(*) FROM issues"; -my $sth = $dbh->prepare($query); +$sth = $dbh->prepare($query); $sth->execute; my $countissue = $sth -> fetchrow_array; is ($countissue ,0, "there is no issue"); @@ -232,20 +251,16 @@ my $issue_id2 = $dbh->last_insert_id( undef, undef, 'issues', undef ); $sth->execute; $countissue = $sth -> fetchrow_array; -is ($countissue,1,"1 issues have been added"); +is ($countissue,1,"1 issue has been added"); #Test AddIssuingCharge -$query = " SELECT count(*) FROM accountlines"; -$sth = $dbh->prepare($query); -$sth->execute; -my $countaccount = $sth -> fetchrow_array; -is ($countaccount,0,"0 accountline exists"); -is( C4::Circulation::AddIssuingCharge( $item_id1, $borrower_id1, 10 ), - 1, "An issuing charge has been added" ); -my $account_id = $dbh->last_insert_id( undef, undef, 'accountlines', undef ); -$sth->execute; -$countaccount = $sth -> fetchrow_array; -is ($countaccount,1,"1 accountline has been added"); +$query = " SELECT * FROM accountlines"; +my $acc_sth = $dbh->prepare($query); +$acc_sth->execute; +my $account = $acc_sth -> fetchall_arrayref({}); +ok (scalar(@$account) == 1 && $account->[0]{accounttype} eq "Rent","accountline has been added") + or diag( Dumper($account) ); + #Test AddRenewal my $datedue3 = @@ -256,6 +271,10 @@ like( qr/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/, "AddRenewal returns a date" ); +$acc_sth->execute; +$account = $acc_sth -> fetchall_arrayref({}); +ok (scalar(@$account) == 2 && $account->[1]{accounttype} eq "Rent","another accountline has been added") + or diag( Dumper($account) ); #Test GetBiblioIssues is( GetBiblioIssues(), undef, "GetBiblio Issues without parameters" ); -- 2.7.4 From srdjan at catalyst.net.nz Fri Jun 10 02:59:31 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Fri, 10 Jun 2016 12:59:31 +1200 Subject: [Koha-patches] [PATCH] Bug 14803: Reload checkouts table on renewal Message-ID: <1465520371-21521-1-git-send-email-srdjan@catalyst.net.nz> svc/checkouts: get real rental charges for patron, rather than itemtype indication --- koha-tmpl/intranet-tmpl/prog/js/checkouts.js | 2 ++ svc/checkouts | 14 ++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js b/koha-tmpl/intranet-tmpl/prog/js/checkouts.js index bf419d7..9643d0e 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js +++ b/koha-tmpl/intranet-tmpl/prog/js/checkouts.js @@ -2,6 +2,7 @@ $(document).ready(function() { $.ajaxSetup ({ cache: false }); var barcodefield = $("#barcode"); + var issuesTable; // Handle the select all/none links for checkouts table columns $("#CheckAllRenewals").on("click",function(){ @@ -96,6 +97,7 @@ $(document).ready(function() { var content = ""; if ( data.renew_okay ) { + issuesTable.api().ajax.reload(); content = CIRCULATION_RENEWED_DUE + " " + data.date_due; $('#date_due_' + data.itemnumber).replaceWith( data.date_due ); } else { diff --git a/svc/checkouts b/svc/checkouts index e613126..5cabdee 100755 --- a/svc/checkouts +++ b/svc/checkouts @@ -63,7 +63,7 @@ binmode STDOUT, ":encoding(UTF-8)"; print $input->header( -type => 'text/plain', -charset => 'UTF-8' ); my @parameters; -my $sql = ' +my $sql = <preference('item-level_itypes'); my @checkouts_today; my @checkouts_previous; while ( my $c = $sth->fetchrow_hashref() ) { - my ($charge) = GetIssuingCharges( $c->{itemnumber}, $c->{borrowernumber} ); my $fine = GetFine( $c->{itemnumber}, $c->{borrowernumber} ); my ( $can_renew, $can_renew_error ) = @@ -159,7 +165,7 @@ while ( my $c = $sth->fetchrow_hashref() ) { branchcode => $c->{branchcode}, branchname => $c->{branchname}, itemcallnumber => $c->{itemcallnumber} || q{}, - charge => $charge, + charge => $c->{amountoutstanding} || 0.00, fine => $fine, price => $c->{replacementprice} || q{}, can_renew => $can_renew, -- 2.7.4 From srdjan at catalyst.net.nz Mon Jun 13 05:22:05 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Mon, 13 Jun 2016 15:22:05 +1200 Subject: [Koha-patches] [PATCH] Bug 7703 - QA Followup Message-ID: <1465788125-1607-1-git-send-email-srdjan@catalyst.net.nz> From: Kyle M Hall Signed-off-by: Srdjan --- C4/Biblio.pm | 2 ++ C4/Items.pm | 2 ++ 2 files changed, 4 insertions(+) diff --git a/C4/Biblio.pm b/C4/Biblio.pm index ae1f2f3..3b18064 100644 --- a/C4/Biblio.pm +++ b/C4/Biblio.pm @@ -1072,6 +1072,8 @@ sub GetBiblio { sub GetBiblioItemInfosOf { my @biblioitemnumbers = @_; + return unless @biblioitemnumbers; + my $biblioitemnumber_values = @biblioitemnumbers ? join( ',', @biblioitemnumbers ) : "''"; my $query = " diff --git a/C4/Items.pm b/C4/Items.pm index 651e590..cdf17e4 100644 --- a/C4/Items.pm +++ b/C4/Items.pm @@ -1195,6 +1195,8 @@ sub GetItemsCount { sub GetItemInfosOf { my @itemnumbers = @_; + return unless @itemnumbers; + my $itemnumber_values = @itemnumbers ? join( ',', @itemnumbers ) : "''"; my $query = " -- 2.7.4 From srdjan at catalyst.net.nz Mon Jun 13 05:23:21 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Mon, 13 Jun 2016 15:23:21 +1200 Subject: [Koha-patches] [PATCH] Bug 7703 - QA Followup 2 Message-ID: <1465788201-2102-1-git-send-email-srdjan@catalyst.net.nz> From: Kyle M Hall Signed-off-by: Srdjan --- koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt | 7 ++++--- reserve/request.pl | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt index 1f01a69..eb00fee 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt @@ -610,11 +610,12 @@ function checkMultiHold() {
    [% IF ( borrowernumber ) %] [% IF ( override_required ) %] - + [% ELSIF ( none_available ) %] - + + Place holds for all records with available items. No holds will be placed for records with no items. [% ELSE %] - + [% END %] [% END %]
    diff --git a/reserve/request.pl b/reserve/request.pl index 1826e00..3b509cc 100755 --- a/reserve/request.pl +++ b/reserve/request.pl @@ -297,7 +297,7 @@ foreach my $biblionumber (@biblionumbers) { } if (!@itemnumbers) { - $template->param('noitems' => 1); + $template->param('noitems' => 1) unless ( $multihold ); $biblioloopiter{noitems} = 1; } -- 2.7.4 From srdjan at catalyst.net.nz Mon Jun 13 05:40:46 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Mon, 13 Jun 2016 15:40:46 +1200 Subject: [Koha-patches] [PATCH] Bug 16716: Replaced wrong GROUP BY with DISTINCT Message-ID: <1465789246-7962-1-git-send-email-srdjan@catalyst.net.nz> --- C4/Koha.pm | 5 ++--- C4/Members.pm | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/C4/Koha.pm b/C4/Koha.pm index 7fe07f1..bb35811 100644 --- a/C4/Koha.pm +++ b/C4/Koha.pm @@ -1024,8 +1024,8 @@ sub GetAuthorisedValues { my @results; my $dbh = C4::Context->dbh; my $query = qq{ - SELECT * - FROM authorised_values + SELECT DISTINCT av.* + FROM authorised_values av }; $query .= qq{ LEFT JOIN authorised_values_branches ON ( id = av_id ) @@ -1043,7 +1043,6 @@ sub GetAuthorisedValues { if(@where_strings > 0) { $query .= " WHERE " . join(" AND ", @where_strings); } - $query .= " GROUP BY lib"; $query .= ' ORDER BY category, ' . ( $opac ? 'COALESCE(lib_opac, lib)' : 'lib, lib_opac' diff --git a/C4/Members.pm b/C4/Members.pm index 383799d..30c3b67 100644 --- a/C4/Members.pm +++ b/C4/Members.pm @@ -1423,7 +1423,7 @@ sub GetborCatFromCatType { my $dbh = C4::Context->dbh; my $request = qq{ - SELECT categories.categorycode, categories.description + SELECT DISTINCT categories.categorycode, categories.description FROM categories }; $request .= qq{ @@ -1431,9 +1431,9 @@ sub GetborCatFromCatType { } if $branch_limit; if($action) { $request .= " $action "; - $request .= " AND (branchcode = ? OR branchcode IS NULL) GROUP BY description" if $branch_limit; + $request .= " AND (branchcode = ? OR branchcode IS NULL)" if $branch_limit; } else { - $request .= " WHERE branchcode = ? OR branchcode IS NULL GROUP BY description" if $branch_limit; + $request .= " WHERE branchcode = ? OR branchcode IS NULL" if $branch_limit; } $request .= " ORDER BY categorycode"; -- 2.7.4 From srdjan at catalyst.net.nz Tue Jun 14 06:11:23 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Tue, 14 Jun 2016 16:11:23 +1200 Subject: [Koha-patches] [PATCH] Bug 16720: Remove DBIx ActionLogs.pm Message-ID: <1465877483-21826-1-git-send-email-srdjan@catalyst.net.nz> From: Tomas Cohen Arazi The update_dbix_class_files.pl script generates ActionLog.pm instead, which is already on the source tree. To test: - Apply the patch => SUCCESS: Koha/Schema/Result/ActionLogs.pm is removed - Run: $ mysql -uroot > CREATE DATABASE dbic; \q $ mysql -uroot dbic < kohaclone/installer/data/mysql/kohastructure.sql $ misc/devel/update_dbix_class_files.pl --db_name dbic --db_user root => SUCCESS: Koha/Schema/Result/ActionLogs.pm is not re-generated - Run: $ git grep ActionLogs => SUCCESS: There's no code using it - Sign off Signed-off-by: Srdjan --- Koha/Schema/Result/ActionLogs.pm | 90 ---------------------------------------- 1 file changed, 90 deletions(-) delete mode 100644 Koha/Schema/Result/ActionLogs.pm diff --git a/Koha/Schema/Result/ActionLogs.pm b/Koha/Schema/Result/ActionLogs.pm deleted file mode 100644 index 13b8cc2..0000000 --- a/Koha/Schema/Result/ActionLogs.pm +++ /dev/null @@ -1,90 +0,0 @@ -package Koha::Schema::Result::ActionLogs; - -# Created by DBIx::Class::Schema::Loader -# DO NOT MODIFY THE FIRST PART OF THIS FILE - -use strict; -use warnings; - -use base 'DBIx::Class::Core'; - - -=head1 NAME - -Koha::Schema::Result::ActionLogs - -=cut - -__PACKAGE__->table("action_logs"); - -=head1 ACCESSORS - -=head2 action_id - - data_type: 'integer' - is_auto_increment: 1 - is_nullable: 0 - -=head2 timestamp - - data_type: 'timestamp' - default_value: current_timestamp - is_nullable: 0 - -=head2 user - - data_type: 'integer' - default_value: 0 - is_nullable: 0 - -=head2 module - - data_type: 'text' - is_nullable: 1 - -=head2 action - - data_type: 'text' - is_nullable: 1 - -=head2 object - - data_type: 'integer' - is_nullable: 1 - -=head2 info - - data_type: 'text' - is_nullable: 1 - -=cut - -__PACKAGE__->add_columns( - "action_id", - { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, - "timestamp", - { - data_type => "timestamp", - default_value => \"current_timestamp", - is_nullable => 0, - }, - "user", - { data_type => "integer", default_value => 0, is_nullable => 0 }, - "module", - { data_type => "text", is_nullable => 1 }, - "action", - { data_type => "text", is_nullable => 1 }, - "object", - { data_type => "integer", is_nullable => 1 }, - "info", - { data_type => "text", is_nullable => 1 }, -); -__PACKAGE__->set_primary_key("action_id"); - - -# Created by DBIx::Class::Schema::Loader v0.07000 @ 2012-09-02 08:44:15 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:9VN0SGNBYM/thO7QzQB4Bg - - -# You can replace this text with custom content, and it will be preserved on regeneration -1; -- 2.7.4 From srdjan at catalyst.net.nz Tue Jun 14 06:19:46 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Tue, 14 Jun 2016 16:19:46 +1200 Subject: [Koha-patches] [PATCH] Bug 16693: Remove reserve/renewscript.pl Message-ID: <1465877986-24785-1-git-send-email-srdjan@catalyst.net.nz> From: Julian Maurice It is not used since bug 11703 Signed-off-by: Srdjan --- reserve/renewscript.pl | 142 ------------------------------------------------- 1 file changed, 142 deletions(-) delete mode 100755 reserve/renewscript.pl diff --git a/reserve/renewscript.pl b/reserve/renewscript.pl deleted file mode 100755 index a1e7912..0000000 --- a/reserve/renewscript.pl +++ /dev/null @@ -1,142 +0,0 @@ -#!/usr/bin/perl - -#written 18/1/2000 by chris at katipo.co.nz -#script to renew items from the web - -# Copyright 2000-2002 Katipo Communications -# -# 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 strict; -use warnings; -use CGI qw ( -utf8 ); -use C4::Circulation; -use C4::Context; -use C4::Items; -use C4::Auth; -use URI::Escape; -use Koha::DateUtils; -my $input = new CGI; - -#Set Up User_env -# And assures user is loggedin and has correct accreditations. - -my ( $template, $loggedinuser, $cookie ) = get_template_and_user( - { - template_name => "members/moremember.tt", - query => $input, - type => "intranet", - authnotrequired => 0, - flagsrequired => { circulate => 'circulate_remaining_permissions' }, - debug => 0, - } -); - -# -# find items to renew, all items or a selection of items -# - -my @data; -if ( $input->param('renew_all') ) { - @data = $input->multi_param('all_items[]'); -} -else { - @data = $input->multi_param('items[]'); -} - -my @barcodes; -if ( $input->param('return_all') ) { - @barcodes = $input->multi_param('all_barcodes[]'); -} -else { - @barcodes = $input->multi_param('barcodes[]'); -} - -my $branch = $input->param('branch'); -my $datedue; -if ( $input->param('newduedate') ) { - $datedue = dt_from_string( scalar $input->param('newduedate') ); - $datedue->set_hour(23); - $datedue->set_minute(59); -} - -# warn "barcodes : @barcodes"; -# -# renew items -# -my $cardnumber = $input->param("cardnumber"); -my $borrowernumber = $input->param("borrowernumber"); -my $exemptfine = $input->param("exemptfine") || 0; -my $override_limit = $input->param("override_limit") || 0; -my $failedrenews = q{}; -foreach my $itemno (@data) { - - # check status before renewing issue - my ( $renewokay, $error ) = - CanBookBeRenewed( $borrowernumber, $itemno, $override_limit ); - if ($renewokay) { - AddRenewal( $borrowernumber, $itemno, $branch, $datedue ); - } - else { - $failedrenews .= "&failedrenew=$itemno"; - } -} -my $failedreturn = q{}; -foreach my $barcode (@barcodes) { - - # check status before returning issue - - #System Preference Handling During Check-in In Patron Module - my $itemnumber; - $itemnumber = GetItemnumberFromBarcode($barcode); - if ($itemnumber) { - if ( C4::Context->preference("InProcessingToShelvingCart") ) { - my $item = GetItem($itemnumber); - if ( $item->{'location'} eq 'PROC' ) { - $item->{'location'} = 'CART'; - ModItem( $item, $item->{'biblionumber'}, - $item->{'itemnumber'} ); - } - } - - if ( C4::Context->preference("ReturnToShelvingCart") ) { - my $item = GetItem($itemnumber); - $item->{'location'} = 'CART'; - ModItem( $item, $item->{'biblionumber'}, $item->{'itemnumber'} ); - } - } - - my ( $returned, $messages, $issueinformation, $borrower ) = - AddReturn( $barcode, $branch, $exemptfine ); - $failedreturn .= "&failedreturn=$barcode" unless ($returned); -} - -# -# redirection to the referrer page -# -if ( $input->param('destination') eq "circ" ) { - $cardnumber = uri_escape_utf8($cardnumber); - print $input->redirect( '/cgi-bin/koha/circ/circulation.pl?findborrower=' - . $cardnumber - . $failedrenews - . $failedreturn ); -} -else { - print $input->redirect( - '/cgi-bin/koha/members/moremember.pl?borrowernumber=' - . $borrowernumber - . $failedrenews - . $failedreturn ); -} -- 2.7.4 From juan.sieira at xercode.es Wed Jun 15 19:22:35 2016 From: juan.sieira at xercode.es (Juan Romay Sieira) Date: Wed, 15 Jun 2016 19:22:35 +0200 Subject: [Koha-patches] [PATCH] Bug 16746 - Can not find duplicated authorities cataloguing a new one Message-ID: <1466011355-11379-1-git-send-email-juan.sieira@xercode.es> Signed-off-by: Juan Romay Sieira --- C4/AuthoritiesMarc.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/C4/AuthoritiesMarc.pm b/C4/AuthoritiesMarc.pm index 4332c67..0d643f1 100644 --- a/C4/AuthoritiesMarc.pm +++ b/C4/AuthoritiesMarc.pm @@ -829,7 +829,7 @@ sub FindDuplicateAuthority { } } my $searcher = Koha::SearchEngine::Search->new({index => $Koha::SearchEngine::AUTHORITIES_INDEX}); - my ($error, $results, $total_hits) = $searcher->simple_search_compat( $query, 0, 1 ); + my ($error, $results, $total_hits) = $searcher->simple_search_compat( $query, 0, 1, [ "authorityserver" ]); # there is at least 1 result => return the 1st one if (!defined $error && @{$results} ) { my $marcrecord = C4::Search::new_record_from_zebra( -- 2.1.4 From srdjan at catalyst.net.nz Fri Jun 17 04:13:20 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Fri, 17 Jun 2016 14:13:20 +1200 Subject: [Koha-patches] [PATCH] Bug 14803: Reload checkouts table on renewal Message-ID: <1466129600-3390-1-git-send-email-srdjan@catalyst.net.nz> svc/checkouts: get real rental charges for patron, rather than itemtype indication --- koha-tmpl/intranet-tmpl/prog/js/checkouts.js | 2 ++ svc/checkouts | 16 +++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js b/koha-tmpl/intranet-tmpl/prog/js/checkouts.js index bf419d7..9643d0e 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js +++ b/koha-tmpl/intranet-tmpl/prog/js/checkouts.js @@ -2,6 +2,7 @@ $(document).ready(function() { $.ajaxSetup ({ cache: false }); var barcodefield = $("#barcode"); + var issuesTable; // Handle the select all/none links for checkouts table columns $("#CheckAllRenewals").on("click",function(){ @@ -96,6 +97,7 @@ $(document).ready(function() { var content = ""; if ( data.renew_okay ) { + issuesTable.api().ajax.reload(); content = CIRCULATION_RENEWED_DUE + " " + data.date_due; $('#date_due_' + data.itemnumber).replaceWith( data.date_due ); } else { diff --git a/svc/checkouts b/svc/checkouts index e613126..475e7e6 100755 --- a/svc/checkouts +++ b/svc/checkouts @@ -25,7 +25,7 @@ use JSON qw(to_json); use C4::Auth qw(check_cookie_auth haspermission get_session); use C4::Biblio qw(GetMarcBiblio GetFrameworkCode GetRecordValue ); -use C4::Circulation qw(GetIssuingCharges CanBookBeRenewed GetRenewCount GetSoonestRenewDate); +use C4::Circulation qw(CanBookBeRenewed GetRenewCount GetSoonestRenewDate); use C4::Koha qw(GetAuthorisedValueByCode); use C4::Overdues qw(GetFine); use C4::Context; @@ -63,7 +63,7 @@ binmode STDOUT, ":encoding(UTF-8)"; print $input->header( -type => 'text/plain', -charset => 'UTF-8' ); my @parameters; -my $sql = ' +my $sql = <preference('item-level_itypes'); my @checkouts_today; my @checkouts_previous; while ( my $c = $sth->fetchrow_hashref() ) { - my ($charge) = GetIssuingCharges( $c->{itemnumber}, $c->{borrowernumber} ); my $fine = GetFine( $c->{itemnumber}, $c->{borrowernumber} ); my ( $can_renew, $can_renew_error ) = @@ -159,7 +165,7 @@ while ( my $c = $sth->fetchrow_hashref() ) { branchcode => $c->{branchcode}, branchname => $c->{branchname}, itemcallnumber => $c->{itemcallnumber} || q{}, - charge => $charge, + charge => $c->{amountoutstanding} || 0.00, fine => $fine, price => $c->{replacementprice} || q{}, can_renew => $can_renew, -- 2.7.4 From srdjan at catalyst.net.nz Fri Jun 17 04:13:32 2016 From: srdjan at catalyst.net.nz (Srdjan) Date: Fri, 17 Jun 2016 14:13:32 +1200 Subject: [Koha-patches] [PATCH] bug 14803: KOHA.Checkouts js object Message-ID: <1466129612-3513-1-git-send-email-srdjan@catalyst.net.nz> * Use javascript to: - update fines/checkouts info - show/hide checkouts form and messages * Created svc/patron/fines --- circ/circulation.pl | 14 ----- .../prog/en/includes/blocked-fines.inc | 16 ++--- .../prog/en/modules/circ/circulation.tt | 72 ++++++++-------------- .../prog/en/modules/members/moremember.tt | 6 +- koha-tmpl/intranet-tmpl/prog/js/checkouts.js | 36 +++++++++++ members/moremember.pl | 3 - svc/patron/fines | 40 ++++++++++++ 7 files changed, 110 insertions(+), 77 deletions(-) create mode 100755 svc/patron/fines diff --git a/circ/circulation.pl b/circ/circulation.pl index b2201cf..11bc8dd 100755 --- a/circ/circulation.pl +++ b/circ/circulation.pl @@ -261,7 +261,6 @@ if ($findborrower) { # get the borrower information..... if ($borrowernumber) { $borrower = GetMemberDetails( $borrowernumber, 0 ); - my ( $od, $issue, $fines ) = GetMemberIssuesAndFines( $borrowernumber ); # Warningdate is the date that the warning starts appearing my ( $today_year, $today_month, $today_day) = Today(); @@ -291,12 +290,6 @@ if ($borrowernumber) { $template->param("returnbeforeexpiry" => 1); } } - $template->param( - overduecount => $od, - issuecount => $issue, - finetotal => $fines - ); - if ( IsDebarred($borrowernumber) ) { $template->param( 'userdebarred' => $borrower->{debarred}, @@ -411,9 +404,6 @@ if (@$barcodes) { } } - # FIXME If the issue is confirmed, we launch another time GetMemberIssuesAndFines, now display the issue count after issue - my ( $od, $issue, $fines ) = GetMemberIssuesAndFines($borrowernumber); - if ($question->{RESERVE_WAITING} or $question->{RESERVED}){ $template->param( reserveborrowernumber => $question->{'resborrowernumber'} @@ -424,10 +414,6 @@ if (@$barcodes) { itembiblionumber => $getmessageiteminfo->{'biblionumber'} ); - - - $template_params->{issuecount} = $issue; - if ( $iteminfo ) { $iteminfo->{subtitle} = GetRecordValue('subtitle', GetMarcBiblio($iteminfo->{biblionumber}), GetFrameworkCode($iteminfo->{biblionumber})); $template_params->{item} = $iteminfo; diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/blocked-fines.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/blocked-fines.inc index 596c0c7..547fa7f 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/blocked-fines.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/blocked-fines.inc @@ -1,14 +1,11 @@ -[% USE Price %] -[% SET NoIssuesCharge = Koha.Preference('noissuescharge') %] - -[% IF NoIssuesCharge && fines > NoIssuesCharge %] -
  • + +
  • -[% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt index f8666bd..fd9ce38 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt @@ -23,6 +23,9 @@ [% INCLUDE 'strings.inc' %] [% INCLUDE 'datatables.inc' %] [% INCLUDE 'columns_settings.inc' %] + [% INCLUDE 'timepicker.inc' %] @@ -82,6 +85,10 @@ function toggle_onsite_checkout(){ function Dopop(link) { var newin = window.open(link, 'popup', 'width=600,height=400,resizable=1,toolbar=0,scrollbars=1,top'); } + +KOHA.Checkouts.DisallowIssue = [% noissues ? "true" : "false" %]; +KOHA.Checkouts.ForceAllowIssue = [% forceallow ? "true" : "false" %]; +KOHA.Checkouts.ForceOnSiteCheckouts = [% Koha.Preference('OnSiteCheckouts') && Koha.Preference('OnSiteCheckoutsForce') ? "true" : "false" %]; $(document).ready(function() { $('#mainform').on('submit',function() { if ($("#barcode") && $("#barcode").val()) { @@ -424,9 +431,7 @@ $(document).ready(function() { [% IF ( RESERVED || ISSUED_TO_ANOTHER ) && (CAN_user_reserveforothers_place_holds ) %] - [% UNLESS noissues %] - - [% END %] + [% END %] [% END %] @@ -589,7 +594,6 @@ No patron matched [% message %]
    Error: This patron has requested their circulation history be anonymized on check-in, but the AnonymousPatron system preference is empty or incorrect.
    [% END %] -[% IF ( !noissues ) || ( Koha.Preference('OnSiteCheckouts') && Koha.Preference('OnSiteCheckoutsForce') )%]
    @@ -622,7 +626,6 @@ No patron matched [% message %]
    - [% UNLESS ( noissues && Koha.Preference('OnSiteCheckoutsForce') ) %] [% IF ( SpecifyDueDate ) %]
    Specify due date [% INCLUDE 'date-format.inc' %]:
    @@ -640,10 +643,8 @@ No patron matched [% message %]
    [% END %] - [% END %] - [% UNLESS ( noissues ) %] -
    +
    [% IF NEEDSCONFIRMATION %] [% ELSE %] @@ -670,19 +671,17 @@ No patron matched [% message %]
    [% END %] - [% END %] [% IF Koha.Preference('OnSiteCheckouts') %]
    - [% IF noissues %] -
    +
    - [% ELSE %] +
    - [% END %] +
    [% END %] @@ -704,35 +703,20 @@ No patron matched [% message %] [% END %]
    -[% END %] - -[% IF ( noissues ) %] - [% IF ( Koha.Preference('OnSiteCheckouts') && Koha.Preference('OnSiteCheckoutsForce') ) %] -
    - [% ELSE %] -
    - [% END %] -[% ELSE %]
    -[% END %] - - [% IF ( noissues ) %] - [% IF ( Koha.Preference('OnSiteCheckouts') && Koha.Preference('OnSiteCheckoutsForce') ) %] -
    - [% ELSE %] +
    +

    Attention:

    +
    + [% IF !( Koha.Preference('OnSiteCheckouts') && Koha.Preference('OnSiteCheckoutsForce') ) %]

    Checking out to [% INCLUDE 'patron-title.inc' %]

    -
    [% END %] -

    - Cannot check out! - [% IF ( Koha.Preference('OnSiteCheckouts') && Koha.Preference('OnSiteCheckoutsForce') ) %] - Only on-site checkouts are allowed - [% END %] -

    - [% ELSE %] -
    -

    Attention:

    - [% END %] +

    + Cannot check out! + [% IF ( Koha.Preference('OnSiteCheckouts') && Koha.Preference('OnSiteCheckoutsForce') ) %] + Only on-site checkouts are allowed + [% END %] +

    +
      @@ -786,8 +770,8 @@ No patron matched [% message %]
      View restrictions - [% IF (noissues && borrowernumber && CAN_user_circulate_force_checkout) %] - + [% IF (borrowernumber && CAN_user_circulate_force_checkout) %] + Override restriction temporarily [% END %] @@ -885,11 +869,7 @@ No patron matched [% message %]
      • - [% IF ( issuecount ) %] - [% issuecount %] Checkout(s) - [% ELSE %] - 0 Checkouts - [% END %] + 0 Checkout(s)
      • [% IF relatives_issues_count %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt index 80a80a9..c092aa2 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt @@ -173,9 +173,7 @@ function validate1(date) { [% ELSE %] [% IF ( was_renewed ) %]
        Patron's account has been renewed until [% dateexpiry | $KohaDates %]
        [% END %] - [% IF fines %] - [% INCLUDE 'blocked-fines.inc' %] - [% END %] + [% INCLUDE 'blocked-fines.inc' %] [% IF ( flagged ) %]
        @@ -447,7 +445,7 @@ function validate1(date) {
          -
        • [% issuecount %] Checkout(s)
        • +
        • 0 Checkout(s)
        • [% IF relatives_issues_count %]
        • Relatives' checkouts
        • [% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js b/koha-tmpl/intranet-tmpl/prog/js/checkouts.js index 9643d0e..e26970e 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js +++ b/koha-tmpl/intranet-tmpl/prog/js/checkouts.js @@ -1,6 +1,40 @@ +if ( KOHA === undefined ) var KOHA = {}; +KOHA.Checkouts = { + NoIssuesCharge: null, + BorrowerNumber: null, + DisallowIssue: false, + ForceAllowIssue: false, + ForceOnSiteCheckouts: false, + ToggleInput: function( allow_issue ) { + if (KOHA.Checkouts.DisallowIssue) allow_issue = false; + if (KOHA.Checkouts.ForceAllowIssue) allow_issue = true; + + $(".issue-allow").toggle(allow_issue); + $(".issue-disallow").toggle(!allow_issue); + $("#mainform").toggle(allow_issue || KOHA.Checkouts.ForceOnSiteCheckouts); + + if (!allow_issue) { + $(".circmessage.attention").removeClass("attention").addClass("warning"); + } + }, + UpdateCheckoutsAndFees: function(checkouts_only=false) { + $.get( "/cgi-bin/koha/svc/patron/fines", {borrowernumber: KOHA.Checkouts.BorrowerNumber}, function( data ) { + $("#issuecount").text(data.issuecount); + if (checkouts_only) return; + + var noissue = KOHA.Checkouts.NoIssuesCharge && data.owing >= KOHA.Checkouts.NoIssuesCharge; + $("#outstanding-fees").toggle(noissue); + $("#outstanding-fees-amount").text(data.owing_formatted); + KOHA.Checkouts.ToggleInput(!noissue); + } ); + } +} + $(document).ready(function() { $.ajaxSetup ({ cache: false }); + KOHA.Checkouts.UpdateCheckoutsAndFees(); + var barcodefield = $("#barcode"); var issuesTable; @@ -65,6 +99,7 @@ $(document).ready(function() { content = ""; if ( data.returned ) { + KOHA.Checkouts.UpdateCheckoutsAndFees(true); content = CIRCULATION_RETURNED; $(id).parent().parent().addClass('ok'); $('#date_due_' + data.itemnumber).html(CIRCULATION_RETURNED); @@ -97,6 +132,7 @@ $(document).ready(function() { var content = ""; if ( data.renew_okay ) { + KOHA.Checkouts.UpdateCheckoutsAndFees(); issuesTable.api().ajax.reload(); content = CIRCULATION_RENEWED_DUE + " " + data.date_due; $('#date_due_' + data.itemnumber).replaceWith( data.date_due ); diff --git a/members/moremember.pl b/members/moremember.pl index e7c54f4..c6fe21d 100755 --- a/members/moremember.pl +++ b/members/moremember.pl @@ -115,9 +115,6 @@ my $borrowernumber = $input->param('borrowernumber'); my $error = $input->param('error'); $template->param( error => $error ) if ( $error ); -my ( $od, $issue, $fines ) = GetMemberIssuesAndFines($borrowernumber); -$template->param( issuecount => $issue, fines => $fines ); - my $data = GetMember( 'borrowernumber' => $borrowernumber ); if ( not defined $data ) { diff --git a/svc/patron/fines b/svc/patron/fines new file mode 100755 index 0000000..d61df9c --- /dev/null +++ b/svc/patron/fines @@ -0,0 +1,40 @@ +#!/usr/bin/perl + +# Copyright 2016 CatalystIT +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; + +use C4::Service; +use C4::Members qw/GetMemberIssuesAndFines/; +use Koha::Number::Price; + +my ( $query, $response ) = C4::Service->init( borrowers => '*' ); + +my $borrowernumber = $query->param('borrowernumber'); + +my ( $od, $issue, $owing ) = GetMemberIssuesAndFines( $borrowernumber ); + +$response->param( + overduecount => $od, + issuecount => $issue, + owing => $owing || 0.00, + owing_formatted => Koha::Number::Price->new( $owing )->format, +); + +C4::Service->return_success( $response ); -- 2.7.4
Apache $versions{apacheVersion}