[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