[Rt-commit] r4230 - in rt/branches/3.7-EXPERIMENTAL: .
html/Elements lib/RT/Interface/Web sbin
ruz at bestpractical.com
ruz at bestpractical.com
Sat Dec 3 03:46:37 EST 2005
Author: ruz
Date: Sat Dec 3 03:46:36 2005
New Revision: 4230
Added:
rt/branches/3.7-EXPERIMENTAL/lib/RT/Interface/Web/Session.pm
Modified:
rt/branches/3.7-EXPERIMENTAL/ (props changed)
rt/branches/3.7-EXPERIMENTAL/Makefile.in
rt/branches/3.7-EXPERIMENTAL/html/Elements/SetupSessionCookie
rt/branches/3.7-EXPERIMENTAL/sbin/rt-clean-sessions.in
Log:
r1423 at cubic-pc: cubic | 2005-12-03 11:49:23 +0300
r1422 at cubic-pc: cubic | 2005-12-02 23:52:56 +0300
* new RT/Interface/Web/Session.pm
* move code from rt-clean-sessions and SetupSessionCookie to new module
* docs
* add rt-clean-sessions to the Makefile
Modified: rt/branches/3.7-EXPERIMENTAL/Makefile.in
==============================================================================
--- rt/branches/3.7-EXPERIMENTAL/Makefile.in (original)
+++ rt/branches/3.7-EXPERIMENTAL/Makefile.in Sat Dec 3 03:46:36 2005
@@ -418,11 +418,13 @@
chmod +x \
sbin/rt-dump-database \
sbin/rt-setup-database \
- sbin/rt-test-dependencies
+ sbin/rt-test-dependencies \
+ sbin/rt-clean-sessions
-cp -rp \
sbin/rt-dump-database \
sbin/rt-setup-database \
sbin/rt-test-dependencies \
+ sbin/rt-clean-sessions \
$(DESTDIR)/$(RT_SBIN_PATH)
# }}}
Modified: rt/branches/3.7-EXPERIMENTAL/html/Elements/SetupSessionCookie
==============================================================================
--- rt/branches/3.7-EXPERIMENTAL/html/Elements/SetupSessionCookie (original)
+++ rt/branches/3.7-EXPERIMENTAL/html/Elements/SetupSessionCookie Sat Dec 3 03:46:36 2005
@@ -43,55 +43,25 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
-<%ONCE>
-my %backends = (
- mysql => 'Apache::Session::MySQL',
- Pg => 'Apache::Session::Postgres',
-# Oracle => 'Apache::Session::Oracle',
-);
-</%ONCE>
<%INIT>
return if $m->is_subrequest; # avoid reentrancy, as suggested by masonbook
-my %cookies = CGI::Cookie->fetch();
-my $cookiename = "RT_SID_".$RT::rtname.".".$ENV{'SERVER_PORT'};
-$SessionCookie ||= ( $cookies{$cookiename} ? $cookies{$cookiename}->value() : undef ),
-
-my $session_class = $RT::WebSessionClass || $backends{$RT::DatabaseType} || 'Apache::Session::File';
-my $pm = "$session_class.pm"; $pm =~ s|::|/|g; require $pm;
-
-my $session_attrs = $backends{$RT::DatabaseType} ? {
- Handle => $RT::Handle->dbh,
- LockHandle => $RT::Handle->dbh,
-} : {
- Directory => $RT::MasonSessionDir,
- LockDirectory => $RT::MasonSessionDir,
-};
-
-eval {
- tie %session, $session_class, $SessionCookie, $session_attrs;
-};
-if ($@) {
-
- # If the session is invalid, create a new session.
- if ( $@ =~ /Object does not/i ) {
- tie %session, $session_class, undef, $session_attrs;
- undef $cookies{$cookiename};
- }
- else {
- die loc("RT couldn't store your session.") . "\n"
- . loc("This may mean that that the directory '[_1]' isn't writable or a database table is missing or corrupt.",
- $RT::MasonSessionDir)
- . "\n\n"
- . $@;
- }
-}
+use RT::Interface::Web::Session;
+
+my %cookies = CGI::Cookie->fetch;
+my $cookiename = "RT_SID_".$RT::rtname;
+$cookiename .= ".".$ENV{'SERVER_PORT'} if $ENV{'SERVER_PORT'};
+$SessionCookie ||= ( $cookies{$cookiename} ? $cookies{$cookiename}->value : undef ),
+
+tie %session, 'RT::Interface::Web::Session', $SessionCookie;
+undef $cookies{$cookiename} unless $session{'_session_id'} eq $SessionCookie;
if ( int $RT::AutoLogoff ) {
my $now = int(time/60);
my $last_update = $session{'_session_last_update'} || 0;
if ( $last_update && ($now - $last_update - $RT::AutoLogoff) > 0 ) {
+ # clean up sessions, but we should leave the session id
%session = (_session_id => $session{'_session_id'});
}
Added: rt/branches/3.7-EXPERIMENTAL/lib/RT/Interface/Web/Session.pm
==============================================================================
--- (empty file)
+++ rt/branches/3.7-EXPERIMENTAL/lib/RT/Interface/Web/Session.pm Sat Dec 3 03:46:36 2005
@@ -0,0 +1,237 @@
+package RT::Interface::Web::Session;
+
+=head1 NAME
+
+RT::Interface::Web::Session - RT web session class
+
+=head1 SYNOPSYS
+
+
+=head1 DESCRIPTION
+
+RT session class and utilities.
+
+CLASS METHODS can be used without creating object instances,
+it's mainly utilities to clean unused session records.
+
+Object is tied hash and can be used to access session data.
+
+=head1 METHODS
+
+=head2 CLASS METHODS
+
+=head3 Class
+
+Returns name of the class that is used as sessions storage.
+
+=cut
+
+sub Class {
+ no warnings 'once';
+ my $class = $RT::WebSessionClass || $backends{$RT::DatabaseType} || 'Apache::Session::File';
+ eval "require $class";
+ die $@ if $@;
+ return $class;
+}
+
+=head3 Backends
+
+Returns hash reference with names of the databases as keys and
+sessions class names as values.
+
+=cut
+
+sub Backends {
+ return {
+ mysql => 'Apache::Session::MySQL',
+ Pg => 'Apache::Session::Postgres',
+ };
+}
+
+=head3 Attributes
+
+Returns hash reference with attributes that are used to create
+new session objects.
+
+=cut
+
+sub Attributes {
+
+ return $_[0]->Backends->{$RT::DatabaseType} ? {
+ Handle => $RT::Handle->dbh,
+ LockHandle => $RT::Handle->dbh,
+ } : {
+ Directory => $RT::MasonSessionDir,
+ LockDirectory => $RT::MasonSessionDir,
+ };
+}
+
+=head3 Ids
+
+Returns array ref with list of the session IDs.
+
+=cut
+
+sub Ids
+{
+ my $self = shift || __PACKAGE__;
+ my $attributes = $self->Attributes;
+ if( $attributes->{Directory} ) {
+ return _IdsDir( $attributes->{Directory} );
+ } else {
+ return _IdsDB( $RT::Handle->dbh );
+ }
+}
+
+sub _IdsDir
+{
+ my ($self, $dir) = @_;
+ require File::Find;
+ my %file;
+ File::Find::find(
+ sub { return unless /^[a-zA-Z0-9]+$/;
+ $file{$_} = (stat($_))[9];
+ },
+ $dir,
+ );
+
+ return [ sort { $file{$a} <=> $file{$b} } keys %file ];
+}
+
+sub _IdsDB
+{
+ my ($self, $dbh) = @_;
+ my $ids = $dbh->selectcol_arrayref("SELECT id FROM sessions ORDER BY LastUpdated DESC");
+ die "couldn't get ids: ". $dbh->errstr if $dbh->errstr;
+ return $ids;
+}
+
+=head3 ClearOld
+
+Takes seconds and deletes all sessions that are older.
+
+=cut
+
+sub ClearOld {
+ my $class = shift || __PACKAGE__;
+ my $attributes = $class->Attributes;
+ if( $attributes->{Directory} ) {
+ return $class->_CleariOldDir( $attributes->{Directory}, @_ );
+ } else {
+ return $class->_ClearOldDB( $RT::Handle->dbh, @_ );
+ }
+}
+
+sub _ClearOldDB
+{
+
+ my ($self, $dbh, $older_than) = @_;
+ my $rows;
+ unless( int $older_than ) {
+ $rows = $dbh->do("DELETE FROM sessions");
+ die "couldn't delete sessions: ". $dbh->errstr unless defined $rows;
+ } else {
+ require POSIX;
+ my $date = POSIX::strftime("%Y-%m-%d %H:%M", localtime( time - int $older_than ) );
+
+ my $sth = $dbh->prepare("DELETE FROM sessions WHERE LastUpdate < ?");
+ die "couldn't prepare query: ". $dbh->errstr unless $sth;
+ $rows = $sth->execute( $date );
+ die "couldn't execute query: ". $dbh->errstr unless defined $rows;
+ }
+
+ $RT::Logger->info("successfuly deleted $rows sessions");
+ return;
+}
+
+sub _ClearOldDir
+{
+ my ($self, $dir, $older_than) = @_;
+
+ require File::Spec if int $older_than;
+
+ my $now = time;
+ my $class = $self->Class;
+ my $attrs = $self->Attributes;
+
+ foreach my $id( @{ $self->Ids } ) {
+ if( int $older_than ) {
+ my $ctime = (stat(File::Spec->catfile($dir,$id)))[9];
+ if( $ctime > $now - $older_than ) {
+ $RT::Logger->debug("skipped session '$id', isn't old");
+ next;
+ }
+ }
+
+ my %session;
+ local $@;
+ eval { tie %session, $class, $id, $attrs };
+ if( $@ ) {
+ $RT::Logger->debug("skipped session '$id', couldn't load: $@");
+ next;
+ }
+ tied(%session)->delete;
+ $RT::Logger->info("successfuly deleted session '$id'");
+ }
+ return;
+}
+
+=head3 ClearByUser
+
+Checks all sessions and if user has more then one session
+then leave only the latest one.
+
+=cut
+
+sub ClearByUser {
+ my $self = shift || __PACKAGE__;
+ my $class = $self->Class;
+ my $attrs = $self->Attributes;
+
+ my %seen = ();
+ foreach my $id( @{ $self->Ids } ) {
+ my %session;
+ local $@;
+ eval { tie %session, $class, $id, $attrs };
+ if( $@ ) {
+ $RT::Logger->debug("skipped session '$id', couldn't load: $@");
+ next;
+ }
+ if( $session{'CurrentUser'} && $session{'CurrentUser'}->id ) {
+ unless( $seen{ $session{'CurrentUser'}->id }++ ) {
+ $RT::Logger->debug("skipped session '$id', first user's session");
+ next;
+ }
+ }
+ tied(%session)->delete;
+ $RT::Logger->info("successfuly deleted session '$id'");
+ }
+}
+
+sub TIEHASH {
+ my $self = shift;
+ my $id = shift;
+
+ my $class = $self->Class;
+ my $attrs = $self->Attributes;
+
+ my %session;
+
+ local $@;
+ eval { tie %session, $class, $id, $attrs };
+ if( $@ ) {
+ if ( $@ =~ /Object does not/i ) {
+ tie %session, $class, undef, $attrs;
+ } else {
+ die loc("RT couldn't store your session.") . "\n"
+ . loc("This may mean that that the directory '[_1]' isn't writable or a database table is missing or corrupt.",
+ $RT::MasonSessionDir)
+ . "\n\n"
+ . $@;
+ }
+ }
+
+ return tied %session;
+}
+
+1;
Modified: rt/branches/3.7-EXPERIMENTAL/sbin/rt-clean-sessions.in
==============================================================================
--- rt/branches/3.7-EXPERIMENTAL/sbin/rt-clean-sessions.in (original)
+++ rt/branches/3.7-EXPERIMENTAL/sbin/rt-clean-sessions.in Sat Dec 3 03:46:36 2005
@@ -19,7 +19,7 @@
Leaves in DB only one session per RT user and sessions that aren't older
than specified(see options).
-Script is safe because data in the sessions is only temporary and can be deleted.
+Script is safe because data in the sessions is temporary and can be deleted.
=head1 OPTIONS
@@ -70,6 +70,8 @@
RT::ConnectToDatabase();
RT::InitLogging();
+require RT::Interface::Web::Session;
+
if( int($RT::AutoLogoff) || $opt{'older'} ) {
my $min;
foreach ($RT::AutoLogoff*60, $opt{'older'}) {
@@ -78,156 +80,9 @@
$min = $_ if $_ < $min;
}
- clear( $min );
+ RT::Interface::Web::Session->ClearOld( $min );
}
-clear_by_user();
+RT::Interface::Web::Session->ClearByUser;
exit(0);
-
-my %backends = (
- mysql => 'Apache::Session::MySQL',
- Pg => 'Apache::Session::Postgres',
-);
-
-sub session_attributes
-{
- return $backends{$RT::DatabaseType} ? {
- Handle => $RT::Handle->dbh,
- LockHandle => $RT::Handle->dbh,
- } : {
- Directory => $RT::MasonSessionDir,
- LockDirectory => $RT::MasonSessionDir,
- };
-}
-
-sub session_class
-{
- no warnings 'once';
- my $class = $RT::WebSessionClass || $backends{$RT::DatabaseType} || 'Apache::Session::File';
- eval "require $class";
- die $@ if $@;
- return $class;
-}
-
-sub session_ids
-{
- my $attributes = session_attributes();
- if( $attributes->{Directory} ) {
- return _ids_dir( $attributes->{Directory} );
- } else {
- return _ids_db( $RT::Handle->dbh );
- }
-}
-
-sub _ids_dir
-{
- my $dir = shift;
- require File::Find;
- my %file;
- File::Find::find(
- sub { return unless /^[a-zA-Z0-9]+$/;
- $file{$_} = (stat($_))[9];
- },
- $dir,
- );
-
- return [ sort { $file{$a} <=> $file{$b} } keys %file ];
-}
-
-sub _ids_db
-{
- my $dbh = shift;
- my $ids = $dbh->selectcol_arrayref("SELECT id FROM sessions ORDER BY LastUpdated DESC");
- die "couldn't get ids: ". $dbh->errstr if $dbh->errstr;
- return $ids;
-}
-
-sub clear
-{
- my $attributes = session_attributes();
- if( $attributes->{Directory} ) {
- return _clear_dir( $attributes->{Directory}, @_ );
- } else {
- return _clear_db( $RT::Handle->dbh, @_ );
- }
-}
-
-sub _clear_db
-{
- my ($dbh, $older_than) = (shift, shift);
- my $rows;
- unless( int $older_than ) {
- $rows = $dbh->do("DELETE FROM sessions");
- die "couldn't delete sessions: ". $dbh->errstr unless defined $rows;
- } else {
- require POSIX;
- my $date = POSIX::strftime("%Y-%m-%d %H:%M", localtime( time - int $older_than ) );
-
- my $sth = $dbh->prepare("DELETE FROM sessions WHERE LastUpdate < ?");
- die "couldn't prepare query: ". $dbh->errstr unless $sth;
- $rows = $sth->execute( $date );
- die "couldn't execute query: ". $dbh->errstr unless defined $rows;
- }
-
- $RT::Logger->info("successfuly deleted $rows sessions");
- return;
-}
-
-sub _clear_dir
-{
- my ($dir, $older_than) = @_;
-
- require File::Spec if int $older_than;
-
- my $now = time;
- my $class = session_class();
- my $attrs = session_attributes();
-
- foreach my $id( @{ session_ids() } ) {
- if( int $older_than ) {
- my $ctime = (stat(File::Spec->catfile($dir,$id)))[9];
- if( $ctime > $now - $older_than ) {
- $RT::Logger->debug("skipped session '$id', isn't old");
- next;
- }
- }
-
- my %session;
- local $@;
- eval { tie %session, $class, $id, $attrs };
- if( $@ ) {
- $RT::Logger->debug("skipped session '$id', couldn't load: $@");
- next;
- }
- tied(%session)->delete;
- $RT::Logger->info("successfuly deleted session '$id'");
- }
- return;
-}
-
-sub clear_by_user
-{
- my $class = session_class();
- my $attrs = session_attributes();
-
- my %seen = ();
- foreach my $id( @{ session_ids() } ) {
- my %session;
- local $@;
- eval { tie %session, $class, $id, $attrs };
- if( $@ ) {
- $RT::Logger->debug("skipped session '$id', couldn't load: $@");
- next;
- }
- if( $session{'CurrentUser'} && $session{'CurrentUser'}->id ) {
- unless( $seen{ $session{'CurrentUser'}->id }++ ) {
- $RT::Logger->debug("skipped session '$id', first user's session");
- next;
- }
- }
- tied(%session)->delete;
- $RT::Logger->info("successfuly deleted session '$id'");
- }
-}
-
More information about the Rt-commit
mailing list