From 0d4a1f2bc2d69491e96fb9564c402c81c5707d06 Mon Sep 17 00:00:00 2001 From: Mike Rylander Date: Mon, 3 Aug 2015 13:27:56 -0400 Subject: [PATCH] LP#1485374: Use client TZ in the database when supplied to the server In LP#1485371 we teach OpenSRF how to discover and pass the client timezone to the server. Now we can use that information to temporarily put the server into that timezone, including database sessions, so that dates and times are calculated and reported based on the timezone of the client. To do that we: * Teach CStore and friends to use the client-supplied time zone * Teach Storage to use $ENV{TZ} for the db timezone inside transactions, and by default except for search-y methods * Teach the TPAC to set the client TZ at login This requires javascript to be enabled in the TPAC, and investigates the client timezone at patron login time. No times are displayed in TPAC interfaces before the patron logs in, so there is no point in detecting the timezone before this point. Signed-off-by: Mike Rylander Signed-off-by: Galen Charlton Signed-off-by: Kathy Lussier Conflicts: Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm Signed-off-by: Jason Stephenson Signed-off-by: Kathy Lussier --- Open-ILS/src/c-apps/oils_sql.c | 111 ++++++++++++++++- .../lib/OpenILS/Application/Storage.pm | 58 +++++++++ .../Application/Storage/Driver/Pg/storage.pm | 114 ++++++++++-------- .../Application/Storage/Publisher/metabib.pm | 41 +++++++ .../perlmods/lib/OpenILS/WWW/EGCatLoader.pm | 57 ++++++--- Open-ILS/src/templates/opac/parts/js.tt2 | 1 + .../src/templates/opac/parts/login/form.tt2 | 1 + 7 files changed, 316 insertions(+), 67 deletions(-) diff --git a/Open-ILS/src/c-apps/oils_sql.c b/Open-ILS/src/c-apps/oils_sql.c index bacb867553..9ea52f6620 100644 --- a/Open-ILS/src/c-apps/oils_sql.c +++ b/Open-ILS/src/c-apps/oils_sql.c @@ -146,6 +146,7 @@ static char* modulename = NULL; int writeAuditInfo( osrfMethodContext* ctx, const char* user_id, const char* ws_id); +static char* _sanitize_tz_name( const char* tz ); static char* _sanitize_savepoint_name( const char* sp ); /** @@ -827,6 +828,8 @@ int beginTransaction( osrfMethodContext* ctx ) { return -1; } + const char* tz = _sanitize_tz_name(ctx->session->session_tz); + if( enforce_pcrud ) { timeout_needs_resetting = 1; const jsonObject* user = verifyUserPCRUD( ctx ); @@ -851,8 +854,36 @@ int beginTransaction( osrfMethodContext* ctx ) { jsonObject* ret = jsonNewObject( getXactId( ctx ) ); osrfAppRespondComplete( ctx, ret ); jsonObjectFree( ret ); - return 0; + + } + + if (tz) { + setenv("TZ",tz,1); + dbi_result tz_res = dbi_conn_queryf( writehandle, "SET LOCAL timezone TO '%s'; -- cstore", tz ); + if( !tz_res ) { + osrfLogError( OSRF_LOG_MARK, "%s: Error setting timezone %s", modulename, tz); + if( !oilsIsDBConnected( writehandle )) { + osrfAppSessionPanic( ctx->session ); + return -1; + } + } else { + dbi_result_free( tz_res ); + } + } else { + unsetenv("TZ"); + dbi_result res = dbi_conn_queryf( writehandle, "SET timezone TO DEFAULT; -- no tz" ); + if( !res ) { + osrfLogError( OSRF_LOG_MARK, "%s: Error resetting timezone", modulename); + if( !oilsIsDBConnected( writehandle )) { + osrfAppSessionPanic( ctx->session ); + return -1; + } + } else { + dbi_result_free( res ); + } } + + return 0; } /** @@ -5826,6 +5857,8 @@ int doJSONSearch ( osrfMethodContext* ctx ) { static jsonObject* doFieldmapperSearch( osrfMethodContext* ctx, osrfHash* class_meta, jsonObject* where_hash, jsonObject* query_hash, int* err ) { + const char* tz = _sanitize_tz_name(ctx->session->session_tz); + // XXX for now... dbhandle = writehandle; @@ -5853,7 +5886,40 @@ static jsonObject* doFieldmapperSearch( osrfMethodContext* ctx, osrfHash* class_ osrfLogDebug( OSRF_LOG_MARK, "%s SQL = %s", modulename, sql ); + // Setting the timezone if requested and not in a transaction + if (!getXactId(ctx)) { + if (tz) { + setenv("TZ",tz,1); + dbi_result tz_res = dbi_conn_queryf( writehandle, "SET timezone TO '%s'; -- cstore", tz ); + if( !tz_res ) { + osrfLogError( OSRF_LOG_MARK, "%s: Error setting timezone %s", modulename, tz); + osrfAppSessionStatus( ctx->session, OSRF_STATUS_INTERNALSERVERERROR, + "osrfMethodException", ctx->request, "Error setting timezone" ); + if( !oilsIsDBConnected( writehandle )) { + osrfAppSessionPanic( ctx->session ); + return -1; + } + } else { + dbi_result_free( tz_res ); + } + } else { + unsetenv("TZ"); + dbi_result res = dbi_conn_queryf( writehandle, "SET timezone TO DEFAULT; -- cstore" ); + if( !res ) { + osrfLogError( OSRF_LOG_MARK, "%s: Error resetting timezone", modulename); + if( !oilsIsDBConnected( writehandle )) { + osrfAppSessionPanic( ctx->session ); + return -1; + } + } else { + dbi_result_free( res ); + } + } + } + + dbi_result result = dbi_conn_query( dbhandle, sql ); + if( NULL == result ) { const char* msg; int errnum = dbi_conn_error( dbhandle, &msg ); @@ -5875,6 +5941,7 @@ static jsonObject* doFieldmapperSearch( osrfMethodContext* ctx, osrfHash* class_ } else { osrfLogDebug( OSRF_LOG_MARK, "Query returned with no errors" ); + } jsonObject* res_list = jsonNewObjectType( JSON_ARRAY ); @@ -7534,4 +7601,46 @@ static char* _sanitize_savepoint_name( const char* sp ) { return safeSpName; } +/** + @brief Remove all but safe character from TZ name + @param tz User-supplied TZ name + @return sanitized TZ name, or NULL + + The caller is expected to free the returned string. Note that + this function exists only because we can't use PQescapeLiteral + without either forking libdbi or abandoning it. +*/ +static char* _sanitize_tz_name( const char* tz ) { + + if (NULL == tz) return NULL; + + const char* safe_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345789_/-+"; + + // PostgreSQL uses NAMEDATALEN-1 as a max length for identifiers, + // and the default value of NAMEDATALEN is 64; that should be long enough + // for our purposes, and it's unlikely that anyone is going to recompile + // PostgreSQL to have a smaller value, so cap the identifier name + // accordingly to avoid the remote chance that someone manages to pass in a + // 12GB savepoint name + const int MAX_LITERAL_NAMELEN = 63; + int len = 0; + len = strlen( tz ); + if (len > MAX_LITERAL_NAMELEN) { + len = MAX_LITERAL_NAMELEN; + } + + char* safeSpName = safe_malloc( len + 1 ); + int i = 0; + int j; + char* found; + for (j = 0; j < len; j++) { + found = strchr(safe_chars, tz[j]); + if (found) { + safeSpName[ i++ ] = found[0]; + } + } + safeSpName[ i ] = '\0'; + return safeSpName; +} + /*@}*/ diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage.pm index 7401846def..3b55c626c5 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage.pm @@ -51,6 +51,64 @@ sub initialize { $log->debug("We seem to be OK...",DEBUG); } +sub register_method { + my $class = shift; + my %args = @_; + + $args{package} ||= ref($class) || $class; + + unless ($args{no_tz_force}) { + my %dup_args = %args; + $dup_args{api_name} = 'no_tz.' . $args{api_name}; + + $args{method} = 'force_db_tz'; + delete $args{package}; + + __PACKAGE__->SUPER::register_method( %dup_args ); + + } + + __PACKAGE__->SUPER::register_method( %args ); + +} + +sub force_db_tz { + my $self = shift; + my $client = shift; + my @args = @_; + + my ($current_xact) = $self->method_lookup('no_tz.open-ils.storage.transaction.current')->run; + + if (!$current_xact && $ENV{TZ}) { + try { + OpenILS::Application::Storage::CDBI->db_Main->do( + 'SET timezone TO ?;', + {}, + $ENV{TZ} + ); + } catch Error with { + $log->error( "Could not set timezone: $ENV{TZ}"); + }; + } + + my $method = $self->method_lookup('no_tz.' . $self->{api_name}); + die unless $method; + + $client->respond( $_ ) for ( $method->run(@args) ); + + if (!$current_xact && $ENV{TZ}) { + try { + OpenILS::Application::Storage::CDBI->db_Main->do( + 'SET timezone TO DEFAULT;', + ); + } catch Error with { + $log->error( "Could not reset default timezone"); + }; + } + + return undef; +} + sub child_init { $log->debug('Running child_init for ' . __PACKAGE__ . '...', DEBUG); diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/storage.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/storage.pm index c9fd3034dc..157aa7cee6 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/storage.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Driver/Pg/storage.pm @@ -60,29 +60,41 @@ throw $e; }; + if ($ENV{TZ}) { + try { + $dbh->do('SET LOCAL timezone TO ?;',{},$ENV{TZ}); + + } catch Error with { + my $e = shift; + $log->debug("Failed to set timezone: $ENV{TZ}", WARN); + }; + } - my $death_cb = $client->session->register_callback( - death => sub { - __PACKAGE__->pg_rollback_xaction; - } - ); - - $log->debug("Registered 'death' callback [$death_cb] for new transaction with Open-ILS XACT-ID [$xact_id]", DEBUG); - - $client->session->session_data( death_cb => $death_cb ); - if ($self->api_name =~ /autocommit$/o) { - $pg->current_xact_is_auto(1); - my $dc_cb = $client->session->register_callback( - disconnect => sub { - my $ses = shift; - $ses->unregister_callback(death => $death_cb); - __PACKAGE__->pg_commit_xaction; + if ($client->session) { # not a subrequest + my $death_cb = $client->session->register_callback( + death => sub { + __PACKAGE__->pg_rollback_xaction; } ); - $log->debug("Registered 'disconnect' callback [$dc_cb] for new transaction with Open-ILS XACT-ID [$xact_id]", DEBUG); - if ($client and $client->session) { - $client->session->session_data( disconnect_cb => $dc_cb ); + + $log->debug("Registered 'death' callback [$death_cb] for new transaction with Open-ILS XACT-ID [$xact_id]", DEBUG); + + $client->session->session_data( death_cb => $death_cb ); + + if ($self->api_name =~ /autocommit$/o) { + $pg->current_xact_is_auto(1); + my $dc_cb = $client->session->register_callback( + disconnect => sub { + my $ses = shift; + $ses->unregister_callback(death => $death_cb); + __PACKAGE__->pg_commit_xaction; + } + ); + $log->debug("Registered 'disconnect' callback [$dc_cb] for new transaction with Open-ILS XACT-ID [$xact_id]", DEBUG); + if ($client and $client->session) { + $client->session->session_data( disconnect_cb => $dc_cb ); + } } } @@ -121,14 +133,16 @@ $success = 0; }; - $pg->current_xact_session->unregister_callback( death => - $pg->current_xact_session->session_data( 'death_cb' ) - ) if ($pg->current_xact_session); - - if ($pg->current_xact_is_auto) { - $pg->current_xact_session->unregister_callback( disconnect => - $pg->current_xact_session->session_data( 'disconnect_cb' ) - ); + if ($pg->current_xact_session) { # not a subrequest + $pg->current_xact_session->unregister_callback( death => + $pg->current_xact_session->session_data( 'death_cb' ) + ) if ($pg->current_xact_session); + + if ($pg->current_xact_is_auto) { + $pg->current_xact_session->unregister_callback( disconnect => + $pg->current_xact_session->session_data( 'disconnect_cb' ) + ); + } } $pg->unset_xact_session; @@ -162,14 +176,16 @@ $success = 0; }; - $pg->current_xact_session->unregister_callback( death => - $pg->current_xact_session->session_data( 'death_cb' ) - ) if ($pg->current_xact_session); - - if ($pg->current_xact_is_auto) { - $pg->current_xact_session->unregister_callback( disconnect => - $pg->current_xact_session->session_data( 'disconnect_cb' ) - ); + if ($pg->current_xact_session) { # not a subrequest + $pg->current_xact_session->unregister_callback( death => + $pg->current_xact_session->session_data( 'death_cb' ) + ) if ($pg->current_xact_session); + + if ($pg->current_xact_is_auto) { + $pg->current_xact_session->unregister_callback( disconnect => + $pg->current_xact_session->session_data( 'disconnect_cb' ) + ); + } } $pg->unset_xact_session; @@ -260,15 +276,17 @@ $pg->set_audit_session( $client->session ); - my $death_cb = $client->session->register_callback( - death => sub { - __PACKAGE__->pg_clear_audit_info; - } - ); - - $log->debug("Registered 'death' callback [$death_cb] for clearing audit information", DEBUG); - - $client->session->session_data( death_cb_ai => $death_cb ); + if ($client->session) { # not a subrequest + my $death_cb = $client->session->register_callback( + death => sub { + __PACKAGE__->pg_clear_audit_info; + } + ); + + $log->debug("Registered 'death' callback [$death_cb] for clearing audit information", DEBUG); + + $client->session->session_data( death_cb_ai => $death_cb ); + } return 1; @@ -292,9 +310,11 @@ $log->debug("Failed to clear audit information: ".$e, INFO); }; - $pg->current_audit_session->unregister_callback( death => - $pg->current_audit_session->session_data( 'death_cb_ai' ) - ) if ($pg->current_audit_session); + if ($pg->current_audit_session) { # not a subrequest + $pg->current_audit_session->unregister_callback( death => + $pg->current_audit_session->session_data( 'death_cb_ai' ) + ) if ($pg->current_audit_session); + } $pg->unset_audit_session; } diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/metabib.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/metabib.pm index 5fea5c7787..7aec5f6f62 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/metabib.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/metabib.pm @@ -150,12 +150,14 @@ sub ordered_records_from_metarecord { # XXX Replace with QP-based search-within- } __PACKAGE__->register_method( api_name => 'open-ils.storage.ordered.metabib.metarecord.records', + no_tz_force => 1, method => 'ordered_records_from_metarecord', api_level => 1, cachable => 1, ); __PACKAGE__->register_method( api_name => 'open-ils.storage.ordered.metabib.metarecord.records.staff', + no_tz_force => 1, method => 'ordered_records_from_metarecord', api_level => 1, cachable => 1, @@ -163,12 +165,14 @@ __PACKAGE__->register_method( __PACKAGE__->register_method( api_name => 'open-ils.storage.ordered.metabib.metarecord.records.atomic', + no_tz_force => 1, method => 'ordered_records_from_metarecord', api_level => 1, cachable => 1, ); __PACKAGE__->register_method( api_name => 'open-ils.storage.ordered.metabib.metarecord.records.staff.atomic', + no_tz_force => 1, method => 'ordered_records_from_metarecord', api_level => 1, cachable => 1, @@ -206,12 +210,14 @@ sub isxn_search { } __PACKAGE__->register_method( api_name => 'open-ils.storage.id_list.biblio.record_entry.search.isbn', + no_tz_force => 1, method => 'isxn_search', api_level => 1, stream => 1, ); __PACKAGE__->register_method( api_name => 'open-ils.storage.id_list.biblio.record_entry.search.issn', + no_tz_force => 1, method => 'isxn_search', api_level => 1, stream => 1, @@ -363,6 +369,7 @@ sub metarecord_copy_count { } __PACKAGE__->register_method( api_name => 'open-ils.storage.metabib.metarecord.copy_count', + no_tz_force => 1, method => 'metarecord_copy_count', api_level => 1, stream => 1, @@ -370,6 +377,7 @@ __PACKAGE__->register_method( ); __PACKAGE__->register_method( api_name => 'open-ils.storage.metabib.metarecord.copy_count.staff', + no_tz_force => 1, method => 'metarecord_copy_count', api_level => 1, stream => 1, @@ -652,6 +660,7 @@ sub biblio_multi_search_full_rec { } __PACKAGE__->register_method( api_name => 'open-ils.storage.biblio.full_rec.multi_search', + no_tz_force => 1, method => 'biblio_multi_search_full_rec', api_level => 1, stream => 1, @@ -659,6 +668,7 @@ __PACKAGE__->register_method( ); __PACKAGE__->register_method( api_name => 'open-ils.storage.biblio.full_rec.multi_search.staff', + no_tz_force => 1, method => 'biblio_multi_search_full_rec', api_level => 1, stream => 1, @@ -713,6 +723,7 @@ sub search_full_rec { } __PACKAGE__->register_method( api_name => 'open-ils.storage.direct.metabib.full_rec.search_fts.value', + no_tz_force => 1, method => 'search_full_rec', api_level => 1, stream => 1, @@ -720,6 +731,7 @@ __PACKAGE__->register_method( ); __PACKAGE__->register_method( api_name => 'open-ils.storage.direct.metabib.full_rec.search_fts.index_vector', + no_tz_force => 1, method => 'search_full_rec', api_level => 1, stream => 1, @@ -879,6 +891,7 @@ sub search_class_fts { for my $class ( qw/title author subject keyword series identifier/ ) { __PACKAGE__->register_method( api_name => "open-ils.storage.metabib.$class.search_fts.metarecord", + no_tz_force => 1, method => 'search_class_fts', api_level => 1, stream => 1, @@ -887,6 +900,7 @@ for my $class ( qw/title author subject keyword series identifier/ ) { ); __PACKAGE__->register_method( api_name => "open-ils.storage.metabib.$class.search_fts.metarecord.unordered", + no_tz_force => 1, method => 'search_class_fts', api_level => 1, stream => 1, @@ -895,6 +909,7 @@ for my $class ( qw/title author subject keyword series identifier/ ) { ); __PACKAGE__->register_method( api_name => "open-ils.storage.metabib.$class.search_fts.metarecord.staff", + no_tz_force => 1, method => 'search_class_fts', api_level => 1, stream => 1, @@ -903,6 +918,7 @@ for my $class ( qw/title author subject keyword series identifier/ ) { ); __PACKAGE__->register_method( api_name => "open-ils.storage.metabib.$class.search_fts.metarecord.staff.unordered", + no_tz_force => 1, method => 'search_class_fts', api_level => 1, stream => 1, @@ -1027,6 +1043,7 @@ sub search_class_fts_count { for my $class ( qw/title author subject keyword series identifier/ ) { __PACKAGE__->register_method( api_name => "open-ils.storage.metabib.$class.search_fts.metarecord_count", + no_tz_force => 1, method => 'search_class_fts_count', api_level => 1, stream => 1, @@ -1035,6 +1052,7 @@ for my $class ( qw/title author subject keyword series identifier/ ) { ); __PACKAGE__->register_method( api_name => "open-ils.storage.metabib.$class.search_fts.metarecord_count.staff", + no_tz_force => 1, method => 'search_class_fts_count', api_level => 1, stream => 1, @@ -1400,6 +1418,7 @@ sub postfilter_search_class_fts { for my $class ( qw/title author subject keyword series identifier/ ) { __PACKAGE__->register_method( api_name => "open-ils.storage.metabib.$class.post_filter.search_fts.metarecord", + no_tz_force => 1, method => 'postfilter_search_class_fts', api_level => 1, stream => 1, @@ -1408,6 +1427,7 @@ for my $class ( qw/title author subject keyword series identifier/ ) { ); __PACKAGE__->register_method( api_name => "open-ils.storage.metabib.$class.post_filter.search_fts.metarecord.staff", + no_tz_force => 1, method => 'postfilter_search_class_fts', api_level => 1, stream => 1, @@ -1891,6 +1911,7 @@ sub postfilter_search_multi_class_fts { __PACKAGE__->register_method( api_name => "open-ils.storage.metabib.post_filter.multiclass.search_fts.metarecord", + no_tz_force => 1, method => 'postfilter_search_multi_class_fts', api_level => 1, stream => 1, @@ -1898,6 +1919,7 @@ __PACKAGE__->register_method( ); __PACKAGE__->register_method( api_name => "open-ils.storage.metabib.post_filter.multiclass.search_fts.metarecord.staff", + no_tz_force => 1, method => 'postfilter_search_multi_class_fts', api_level => 1, stream => 1, @@ -1906,6 +1928,7 @@ __PACKAGE__->register_method( __PACKAGE__->register_method( api_name => "open-ils.storage.metabib.multiclass.search_fts", + no_tz_force => 1, method => 'postfilter_search_multi_class_fts', api_level => 1, stream => 1, @@ -1913,6 +1936,7 @@ __PACKAGE__->register_method( ); __PACKAGE__->register_method( api_name => "open-ils.storage.metabib.multiclass.search_fts.staff", + no_tz_force => 1, method => 'postfilter_search_multi_class_fts', api_level => 1, stream => 1, @@ -2298,6 +2322,7 @@ sub biblio_search_multi_class_fts { __PACKAGE__->register_method( api_name => "open-ils.storage.biblio.multiclass.search_fts.record", + no_tz_force => 1, method => 'biblio_search_multi_class_fts', api_level => 1, stream => 1, @@ -2305,6 +2330,7 @@ __PACKAGE__->register_method( ); __PACKAGE__->register_method( api_name => "open-ils.storage.biblio.multiclass.search_fts.record.staff", + no_tz_force => 1, method => 'biblio_search_multi_class_fts', api_level => 1, stream => 1, @@ -2312,6 +2338,7 @@ __PACKAGE__->register_method( ); __PACKAGE__->register_method( api_name => "open-ils.storage.biblio.multiclass.search_fts", + no_tz_force => 1, method => 'biblio_search_multi_class_fts', api_level => 1, stream => 1, @@ -2319,6 +2346,7 @@ __PACKAGE__->register_method( ); __PACKAGE__->register_method( api_name => "open-ils.storage.biblio.multiclass.search_fts.staff", + no_tz_force => 1, method => 'biblio_search_multi_class_fts', api_level => 1, stream => 1, @@ -2595,6 +2623,7 @@ sub staged_fts { } __PACKAGE__->register_method( api_name => "open-ils.storage.biblio.multiclass.staged.search_fts", + no_tz_force => 1, method => 'staged_fts', api_level => 0, stream => 1, @@ -2602,6 +2631,7 @@ __PACKAGE__->register_method( ); __PACKAGE__->register_method( api_name => "open-ils.storage.biblio.multiclass.staged.search_fts.staff", + no_tz_force => 1, method => 'staged_fts', api_level => 0, stream => 1, @@ -2609,6 +2639,7 @@ __PACKAGE__->register_method( ); __PACKAGE__->register_method( api_name => "open-ils.storage.metabib.multiclass.staged.search_fts", + no_tz_force => 1, method => 'staged_fts', api_level => 0, stream => 1, @@ -2616,6 +2647,7 @@ __PACKAGE__->register_method( ); __PACKAGE__->register_method( api_name => "open-ils.storage.metabib.multiclass.staged.search_fts.staff", + no_tz_force => 1, method => 'staged_fts', api_level => 0, stream => 1, @@ -2650,6 +2682,7 @@ sub FTS_paging_estimate { } __PACKAGE__->register_method( api_name => "open-ils.storage.fts_paging_estimate", + no_tz_force => 1, method => 'FTS_paging_estimate', argc => 5, strict => 1, @@ -2749,6 +2782,7 @@ sub xref_count { } __PACKAGE__->register_method( api_name => "open-ils.storage.search.xref", + no_tz_force => 1, method => 'xref_count', api_level => 1, ); @@ -2763,6 +2797,7 @@ sub abstract_query2str { __PACKAGE__->register_method( api_name => "open-ils.storage.query_parser.abstract_query.canonicalize", + no_tz_force => 1, method => "abstract_query2str", api_level => 1, signature => { @@ -2804,6 +2839,7 @@ sub str2abstract_query { __PACKAGE__->register_method( api_name => "open-ils.storage.query_parser.abstract_query.from_string", + no_tz_force => 1, method => "str2abstract_query", api_level => 1, signature => { @@ -3116,6 +3152,7 @@ sub query_parser_fts { } __PACKAGE__->register_method( api_name => "open-ils.storage.query_parser_search", + no_tz_force => 1, method => 'query_parser_fts', api_level => 1, stream => 1, @@ -3273,6 +3310,7 @@ sub query_parser_fts_wrapper { } __PACKAGE__->register_method( api_name => "open-ils.storage.biblio.multiclass.staged.search_fts", + no_tz_force => 1, method => 'query_parser_fts_wrapper', api_level => 1, stream => 1, @@ -3280,6 +3318,7 @@ __PACKAGE__->register_method( ); __PACKAGE__->register_method( api_name => "open-ils.storage.biblio.multiclass.staged.search_fts.staff", + no_tz_force => 1, method => 'query_parser_fts_wrapper', api_level => 1, stream => 1, @@ -3287,6 +3326,7 @@ __PACKAGE__->register_method( ); __PACKAGE__->register_method( api_name => "open-ils.storage.metabib.multiclass.staged.search_fts", + no_tz_force => 1, method => 'query_parser_fts_wrapper', api_level => 1, stream => 1, @@ -3294,6 +3334,7 @@ __PACKAGE__->register_method( ); __PACKAGE__->register_method( api_name => "open-ils.storage.metabib.multiclass.staged.search_fts.staff", + no_tz_force => 1, method => 'query_parser_fts_wrapper', api_level => 1, stream => 1, diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm index bd9c3df0dd..0bf86c7a20 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm @@ -31,6 +31,7 @@ my $U = 'OpenILS::Application::AppUtils'; use constant COOKIE_SES => 'ses'; use constant COOKIE_LOGGEDIN => 'eg_loggedin'; +use constant COOKIE_TZ => 'client_tz'; use constant COOKIE_PHYSICAL_LOC => 'eg_physical_loc'; use constant COOKIE_SSS_EXPAND => 'eg_sss_expand'; @@ -261,12 +262,15 @@ sub load_common { $ctx->{default_sort} = ($default_sort && $U->is_true($default_sort->enabled)) ? $default_sort->value : ''; + $ctx->{client_tz} = $self->cgi->cookie(COOKIE_TZ) || $ENV{TZ}; $ctx->{referer} = $self->cgi->referer; $ctx->{path_info} = $self->cgi->path_info; $ctx->{full_path} = $ctx->{base_path} . $self->cgi->path_info; $ctx->{unparsed_uri} = $self->apache->unparsed_uri; $ctx->{opac_root} = $ctx->{base_path} . "/opac"; # absolute base url + local $ENV{TZ} = $ctx->{client_tz}; + my $xul_wrapper = ($self->apache->headers_in->get('OILS-Wrapper') || '') =~ /true/; @@ -406,6 +410,7 @@ sub load_login { my $password = $cgi->param('password'); my $org_unit = $ctx->{physical_loc} || $ctx->{aou_tree}->()->id; my $persist = $cgi->param('persist'); + my $client_tz = $cgi->param('client_tz'); # initial log form only return Apache2::Const::OK unless $username and $password; @@ -466,27 +471,41 @@ sub load_login { # both login-related cookies should expire at the same time my $login_cookie_expires = ($persist) ? CORE::time + $response->{payload}->{authtime} : undef; + my $cookie_list = [ + # contains the actual auth token and should be sent only over https + $cgi->cookie( + -name => COOKIE_SES, + -path => '/', + -secure => 1, + -value => $response->{payload}->{authtoken}, + -expires => $login_cookie_expires + ), + # contains only a hint that we are logged in, and is used to + # trigger a redirect to https + $cgi->cookie( + -name => COOKIE_LOGGEDIN, + -path => '/', + -secure => 0, + -value => '1', + -expires => $login_cookie_expires + ) + ]; + + if ($client_tz) { + # contains the client's tz, as passed by the client + # trigger a redirect to https + push @$cookie_list, $cgi->cookie( + -name => COOKIE_TZ, + -path => '/', + -secure => 0, + -value => $client_tz, + -expires => $login_cookie_expires + ); + } + return $self->generic_redirect( $cgi->param('redirect_to') || $acct, - [ - # contains the actual auth token and should be sent only over https - $cgi->cookie( - -name => COOKIE_SES, - -path => '/', - -secure => 1, - -value => $response->{payload}->{authtoken}, - -expires => $login_cookie_expires - ), - # contains only a hint that we are logged in, and is used to - # trigger a redirect to https - $cgi->cookie( - -name => COOKIE_LOGGEDIN, - -path => '/', - -secure => 0, - -value => '1', - -expires => $login_cookie_expires - ) - ] + $cookie_list ); } diff --git a/Open-ILS/src/templates/opac/parts/js.tt2 b/Open-ILS/src/templates/opac/parts/js.tt2 index 2fc0a4f4e9..5cfdebeef5 100644 --- a/Open-ILS/src/templates/opac/parts/js.tt2 +++ b/Open-ILS/src/templates/opac/parts/js.tt2 @@ -146,4 +146,5 @@ var aou_hash = { [% END %] + [%- END; # want_dojo -%] diff --git a/Open-ILS/src/templates/opac/parts/login/form.tt2 b/Open-ILS/src/templates/opac/parts/login/form.tt2 index 165785527f..19319fa042 100644 --- a/Open-ILS/src/templates/opac/parts/login/form.tt2 +++ b/Open-ILS/src/templates/opac/parts/login/form.tt2 @@ -53,6 +53,7 @@ + [% INCLUDE "opac/parts/login/help.tt2" %] -- 2.43.2