[Jifty-commit] r956 - in jifty/trunk: . lib lib/Jifty lib/Jifty/Test/WWW lib/Jifty/Web

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Fri Apr 28 15:50:00 EDT 2006


Author: alexmv
Date: Fri Apr 28 15:49:59 2006
New Revision: 956

Modified:
   jifty/trunk/   (props changed)
   jifty/trunk/lib/Jifty.pm
   jifty/trunk/lib/Jifty/Everything.pm
   jifty/trunk/lib/Jifty/Model/Session.pm
   jifty/trunk/lib/Jifty/Test/WWW/Mechanize.pm
   jifty/trunk/lib/Jifty/Web/Session.pm

Log:
 r12683 at zoq-fot-pik:  chmrr | 2006-04-28 15:49:31 -0400
  * Sessions stored in the database


Modified: jifty/trunk/lib/Jifty.pm
==============================================================================
--- jifty/trunk/lib/Jifty.pm	(original)
+++ jifty/trunk/lib/Jifty.pm	Fri Apr 28 15:49:59 2006
@@ -5,7 +5,7 @@
 use encoding 'utf8';
 # Work around the fact that Time::Local caches thing on first require
 BEGIN { local $ENV{'TZ'} = "GMT";  require Time::Local;}
-our $VERSION = '0.60427';
+our $VERSION = '0.60428';
 
 =head1 NAME
 

Modified: jifty/trunk/lib/Jifty/Everything.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Everything.pm	(original)
+++ jifty/trunk/lib/Jifty/Everything.pm	Fri Apr 28 15:49:59 2006
@@ -38,6 +38,7 @@
 use Jifty::View::Mason::Handler ();
 
 use Jifty::Model::Metadata ();
+use Jifty::Model::Session ();
 
 
 use Jifty::Request ();

Modified: jifty/trunk/lib/Jifty/Model/Session.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Model/Session.pm	(original)
+++ jifty/trunk/lib/Jifty/Model/Session.pm	Fri Apr 28 15:49:59 2006
@@ -1,2 +1,91 @@
-package Jifty::Model::Session; 
-"TRUE, THIS IS A STUB FILE. SORRY";
+use warnings;
+use strict;
+
+=head1 NAME
+
+Jifty::Model::Session - Jifty session tracking
+
+=head1 DESCRIPTION
+
+Every Jifty application automatically inherits this table, which
+tracks session information for the application.  Individual keys in
+the session structure are stored as rows, making session updates take
+constant time, and also reducing the need for locking.
+
+=cut
+
+package Jifty::Model::Session::Schema;
+use Jifty::DBI::Schema;
+
+column session_id => type is 'varchar(32)';
+column key => type is 'text';
+column value => type is 'blob',
+  filters are 'Jifty::DBI::Filter::Storable';
+column created => type is 'timestamp',
+  filters are 'Jifty::DBI::Filter::DateTime';
+column updated => type is 'timestamp',
+  filters are 'Jifty::DBI::Filter::DateTime';
+column key_type => type is 'varchar(32)';
+
+package Jifty::Model::Session;
+
+use base qw( Jifty::Record );
+use DateTime;
+
+=head2 table
+
+Sessions are stored in the table C<_jifty_sessions>.
+
+=cut
+
+sub table {'_jifty_sessions'}
+sub since { '0.60428' }
+sub current_user { return Jifty::CurrentUser->superuser }
+
+=head2 new_session_id
+
+Returns a random new session id.  This is a 32-character hex string.
+
+=cut
+
+sub new_session_id {
+    return Digest::MD5::md5_hex(
+        Digest::MD5::md5_hex( time() . {} . rand() . $$ ) );
+}
+
+=head2 create
+
+Defaults the created and updated times to now.
+
+=cut
+
+sub create {
+    my $self = shift;
+    my %args = (
+        session_id => $self->new_session_id,
+        key_type   => "key",
+        created    => DateTime->now,
+        updated    => DateTime->now,
+        @_,
+    );
+
+    return $self->SUPER::create(%args);
+}
+
+=head2 set_value [VALUE]
+
+Updates the C<updated> column, in addition to setting the value.
+
+=cut
+
+sub set_value {
+    my $self  = shift;
+    my $value = shift;
+
+    return undef unless $self->id;
+
+    $self->set_updated( DateTime->now );
+    $self->_set( column => 'value', value => $value );
+}
+
+1;

Modified: jifty/trunk/lib/Jifty/Test/WWW/Mechanize.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Test/WWW/Mechanize.pm	(original)
+++ jifty/trunk/lib/Jifty/Test/WWW/Mechanize.pm	Fri Apr 28 15:49:59 2006
@@ -13,13 +13,15 @@
 
 =head1 NAME
 
-Jifty::Test::WWW::Mechanize - Subclass of L<Test::WWW::Mechanize> with extra Jifty features
+Jifty::Test::WWW::Mechanize - Subclass of L<Test::WWW::Mechanize> with
+extra Jifty features
 
 =head1 METHODS
 
 =head2 new
 
-Overrides L<Test::WWW::Mechanize>'s C<new> to automatically give the bot a cookie jar.
+Overrides L<Test::WWW::Mechanize>'s C<new> to automatically give the
+bot a cookie jar.
 
 =cut
 
@@ -32,8 +34,8 @@
 
 =head2 moniker_for ACTION, FIELD1 => VALUE1, FIELD2 => VALUE2
 
-Finds the moniker of the first action of type I<ACTION> whose "constructor"
-field I<FIELD1> is I<VALUE1>, and so on.
+Finds the moniker of the first action of type I<ACTION> whose
+"constructor" field I<FIELD1> is I<VALUE1>, and so on.
 
 =cut
 
@@ -63,9 +65,10 @@
 
 =head2 fill_in_action MONIKER, FIELD1 => VALUE1, FIELD2 => VALUE2, ...
 
-Finds the fields on the current page with the names FIELD1, FIELD2, etc in the MONIKER
-action, and fills them in.  Returns the L<HTML::Form> object of the form
-that the action is in, or undef if it can't find all the fields.
+Finds the fields on the current page with the names FIELD1, FIELD2,
+etc in the MONIKER action, and fills them in.  Returns the
+L<HTML::Form> object of the form that the action is in, or undef if it
+can't find all the fields.
 
 =cut
 
@@ -90,11 +93,13 @@
 
 =head2 fill_in_action_ok MONIKER, FIELD1 => VALUE1, FIELD2 => VALUE2, ...
 
-Finds the fields on the current page with the names FIELD1, FIELD2, etc in the MONIKER
-action, and fills them in.  Returns the L<HTML::Form> object of the form
-that the action is in, or undef if it can't find all the fields.
+Finds the fields on the current page with the names FIELD1, FIELD2,
+etc in the MONIKER action, and fills them in.  Returns the
+L<HTML::Form> object of the form that the action is in, or undef if it
+can't find all the fields.
 
-Also, passes if it finds all of the fields and fails if any of the fields are missing.
+Also, passes if it finds all of the fields and fails if any of the
+fields are missing.
 
 =cut
 
@@ -135,8 +140,8 @@
 
 =head2 action_field_value MONIKER, FIELD
 
-Finds the fields on the current page with the names FIELD in the action 
-MONIKER, and returns its value, or undef if it can't be found.
+Finds the fields on the current page with the names FIELD in the
+action MONIKER, and returns its value, or undef if it can't be found.
 
 =cut
 
@@ -153,14 +158,6 @@
     return $input->value;
 }
 
-=head2 field_error_text MONIKER, FIELD
-
-Finds the error span on the current page for the name FIELD in the action
-MONIKER, and returns the text (tags stripped) from it.  (If the field can't be
-found.
-
-=cut
-
 # When it sees something like
 # http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd as a DOCTYPE, this will make
 # it open static/dtd/xhtml1-strict.dtd instead -- great for offline hacking!
@@ -180,6 +177,14 @@
     $_[-1] = 1; # just return please
 };
 
+=head2 field_error_text MONIKER, FIELD
+
+Finds the error span on the current page for the name FIELD in the
+action MONIKER, and returns the text (tags stripped) from it.  (If the
+field can't be found.
+
+=cut
+
 sub field_error_text {
     my $self = shift;
     my $moniker = shift;
@@ -199,8 +204,9 @@
 
 =head2 uri
 
-L<WWW::Mechanize> has a bug where it returns the wrong value for C<uri> after
-redirect.  This fixes that.  See http://rt.cpan.org/NoAuth/Bug.html?id=9059
+L<WWW::Mechanize> has a bug where it returns the wrong value for
+C<uri> after redirect.  This fixes that.  See
+http://rt.cpan.org/NoAuth/Bug.html?id=9059
 
 =cut
 
@@ -208,7 +214,8 @@
 
 =head2 get_html_ok URL
 
-Calls C<get> URL, followed by testing the HTML using L<Test::HTML::Lint>.
+Calls C<get> URL, followed by testing the HTML using
+L<Test::HTML::Lint>.
 
 =cut
 
@@ -222,7 +229,8 @@
 
 =head2 submit_html_ok 
 
-Calls C<submit>, followed by testing the HTML using L<Test::HTML::Lint>.
+Calls C<submit>, followed by testing the HTML using
+L<Test::HTML::Lint>.
 
 =cut
 
@@ -269,7 +277,6 @@
 
     my $session = Jifty::Web::Session->new;
     $session->load($1);
-    $session->_session->release_all_locks();
     return $session;
 }
 

Modified: jifty/trunk/lib/Jifty/Web/Session.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Web/Session.pm	(original)
+++ jifty/trunk/lib/Jifty/Web/Session.pm	Fri Apr 28 15:49:59 2006
@@ -2,231 +2,239 @@
 use strict;
 
 package Jifty::Web::Session;
-use base qw/Jifty::Object Class::Accessor::Fast/;
+use base qw/Jifty::Object/;
 use CGI::Cookie;
-
-# We don't use Class::Accessor::Fast as we want to do our own 'set' and 'get' here
-#__PACKAGE__->mk_accessors(qw(_session));
+use DateTime;
 
 =head1 NAME
 
 Jifty::Web::Session - A Jifty session handler
 
-=head1 DESCRIPTION
-
-* Jifty sessions
-
-* User gets a per-app session cookie in their first response from the server
-* User gets an updated cookie on any request where:
-    1) if the cookie parameters have changed
-    2) if the user's current sessionid doesn't match the cookie's session id
+=cut
 
-* The session cookie is handed out after all processing, but before any page 
-  content is displayed
+=head1 new
 
-* The user gets a cookie even if we're doing a redirect.
+Returns a new, empty session.
 
-* In the future, we might want to not give the user a cookie.
+=cut
 
+sub new {
+    my $class = shift;
+    return bless {}, $class;
+}
 
+=head2 id
 
-* Debugging
+Returns the session's id if it has been loaded, or C<undef> otherwise.
 
-** Should log:
-    * User presented a session cookie
-    * Loaded session from disk
-    * Failed to load session from disk (expired)
-    * Created a new session
-    * Sent a session cookie to the user.
+=cut
 
+sub id {
+    my $self = shift;
+    return $self->loaded ? $self->_session->session_id : undef;
+}
 
-=head2 load
+=head2 load [ID]
 
-Load up the current session from a cookie
+Load up the current session from the given C<ID>, or the appropriate
+cookie (see L</cookie_name>) otherwise.  If both of those fail,
+creates a session in the database.
 
 =cut
 
-
 sub load {
-    my $self = shift;
+    my $self       = shift;
     my $session_id = shift;
 
-    require Apache::Session::File;
-    
     unless ($session_id) {
         my %cookies    = CGI::Cookie->fetch();
         my $cookiename = $self->cookie_name;
-        $session_id    =  $cookies{$cookiename} ? $cookies{$cookiename}->value() : undef;
+        $session_id
+            = $cookies{$cookiename} ? $cookies{$cookiename}->value() : undef;
     }
 
-    $Storable::Deparse = 1;
-    $Storable::Eval    = 1;
-    my %session;
-
-    my $session_dir = Jifty::Util->absolute_path( Jifty->config->framework('Web')->{'SessionDir'} );
-
-    eval {
-        tie %session, 'Apache::Session::File', ( $session_id ? $session_id : undef ),
-                {
-                 Directory     => $session_dir,
-                 LockDirectory => $session_dir,
-                };
-
-            };
-    if ($@) {
-        tie %session, 'Apache::Session::File', undef,
-                {
-                 Directory     => $session_dir,
-                 LockDirectory => $session_dir,
-                };
-    }
+    my $session = Jifty::Model::Session->new;
+    $session->load_by_cols(
+        session_id => $session_id,
+        key_type   => "session"
+        )
+        if $session_id;
 
-    $self->_session( tied(%session) );
-    $session{_session_id} = $session{_session_id} || $session_id;
+    $session->create( key_type => "session" ) unless $session->id;
+    $self->_session($session);
 }
 
 =head2 unload
 
-Flush the session to disk and quit.
+Flush the session, and leaves the session object blank.
 
 =cut
 
 sub unload {
     my $self = shift;
 
-    return unless($self->_session);
-    $self->_session->save();
-    $self->_session->{object_store}->close;
-    $self->_session->release_all_locks();
+    return unless $self->loaded;
     $self->_session(undef);
 }
 
 =head2 loaded
 
-Returns true if the session has already been loaded
+Returns true if the session has already been loaded.
 
 =cut
 
 sub loaded {
     my $self = shift;
-    return $self->_session && $self->get('_session_id');
+    return $self->_session;
 }
 
 sub _session {
     my $self = shift;
     $self->{'_session'} = shift if (@_);
-    return ($self->{'_session'});
+    return ( $self->{'_session'} );
 }
 
-=head2 get KEY
+=head2 get KEY [TYPE]
 
-Returns the value for C<KEY> for the current user's session
+Returns the value for C<KEY> for the current user's session.  C<TYPE>,
+which defaults to "key", allows accessing of other namespaces in the
+session, including "metadata" and "continuation".
 
 =cut
 
 sub get {
-    my $self = shift;
-    my $key = shift;
-    return($self->_session ? $self->_session->FETCH($key) : undef);
-
+    my $self     = shift;
+    my $key      = shift;
+    my $key_type = shift || "key";
+
+    return undef unless $self->loaded;
+
+    my $setting = Jifty::Model::Session->new;
+    $setting->load_by_cols(
+        session_id => $self->id,
+        key_type   => $key_type,
+        key        => $key
+    );
+    return $setting->value;
 }
 
+=head2 set KEY => VALUE, [TYPE]
 
-=head2 set KEY => VALUE
-
-Sets the value C<VALUE> for C<KEY> for the current user's session
+Sets the value C<VALUE> for C<KEY> for the session.  C<TYPE>, which
+defaults to "key", allows values to be set in other namespaces,
+including "metadata" and "continuation".
 
 =cut
 
 sub set {
-    my $self = shift;
-    my $key = shift;
-    my $value = shift;
-
-    ($self->_session ? $self->_session->STORE($key => $value) : undef);
-
+    my $self     = shift;
+    my $key      = shift;
+    my $value    = shift;
+    my $key_type = shift || "key";
+
+    return undef unless $self->loaded;
+    $self->_session->set_updated( DateTime->now );
+
+    my $setting = Jifty::Model::Session->new;
+    $setting->load_by_cols(
+        session_id => $self->id,
+        key_type   => $key_type,
+        key        => $key
+    );
+    if ( $setting->id ) {
+        $setting->set_value($value);
+    } else {
+        $setting->create(
+            session_id => $self->id,
+            key_type   => $key_type,
+            key        => $key,
+            value      => $value
+        );
+    }
 }
 
+=head2 remove KEY, [TYPE]
 
-=head2 remove KEY
-
-Remove key C<KEY> from the cache.
+Remove key C<KEY> from the cache.  C<TYPE> defaults to "key".
 
 =cut
 
 sub remove {
-    my $self = shift;
-    my $key = shift;
-    $self->set($key => undef);
+    my $self     = shift;
+    my $key      = shift;
+    my $key_type = shift || "key";
+
+    return undef unless $self->loaded;
+    $self->_session->set_updated( DateTime->now );
+
+    my $setting = Jifty::Model::Session->new;
+    $setting->load_by_cols(
+        session_id => $self->id,
+        key_type   => $key_type,
+        key        => $key
+    );
+    $setting->delete if $setting->id;
 }
 
+=head2 set_continuation ID CONT
 
-=head2 set_continuation KEY VALUE
-
-Stores a continuation in the session
+Stores a continuation in the session.
 
 =cut
 
-
 sub set_continuation {
     my $self = shift;
-    my $key = shift;
-    my $val = shift;
-
-    $self->set( '_continuation_'.$key => $val);
-
+    $self->set( @_, "continuation" );
 }
 
+=head2 get_continuation ID
 
-
-=head2 get_continuation KEY 
-
-Pulls a continuation from the current session. Expects a continuation id
+Pulls a continuation from the current session. Expects a continuation
+C<ID>.
 
 =cut
 
-sub get_continuation { 
+sub get_continuation {
     my $self = shift;
-    my $key = shift;
-    $self->get('_continuation_'.$key);
+    $self->get( @_, "continuation" );
 
 }
 
-=head2 remove_continuation CONTINUATION_ID
+=head2 remove_continuation ID
 
-Removes a continuation with id CONTINUATION id from the store.
+Removes a continuation with id C<ID> from the store.
 
 =cut
 
 sub remove_continuation {
     my $self = shift;
-    my $key = shift;
-    $self->remove('_continuation_'.$key);
+    $self->remove( @_, "continuation" );
 }
 
-
 =head2 continuations
 
-Return a hash of all the continuations in this session. Keyed by continuation_C<id>.
+Return a hash of all the continuations in this session, keyed by the
+continuations' C<id>.
 
 =cut
 
-
 sub continuations {
     my $self = shift;
-    my %continuations;
-    # XXX TODO: we're deeply abusing the API. that's uncool. We want to replace Apache::Session
-    map { $continuations{$_} = $self->get($_) } grep { /^_continuation_/ } keys %{$self->_session->{'data'}};
-    return %continuations;
-}
-
 
+    return () unless $self->loaded;
 
+    my $conts = Jifty::Model::SessionCollection->new;
+    $conts->limit( column => "key_type",   value => "continuation" );
+    $conts->limit( column => "session_id", value => $self->id );
 
+    my %continuations;
+    $continuations{ $_->key } = $_->value while $_ = $conts->next;
+    return %continuations;
+}
 
 =head2 set_cookie
 
-Sets the session cookie
+Sets the session cookie.
 
 =cut
 
@@ -239,22 +247,23 @@
         = $cookies{$cookie_name} ? $cookies{$cookie_name}->value() : undef;
     my $cookie = new CGI::Cookie(
         -name    => $cookie_name,
-        -value   => $self->get('_session_id'),
-        -expires => $self->get('_expires'),
+        -value   => $self->id,
+        -expires => $self->expires,
     );
 
     # XXX TODO might need to change under mod_perl
     if ( not $cookies{$cookie_name}
         or ( $cookies{$cookie_name} ne $cookie->as_string ) )
     {
-        Jifty->web->response->add_header( 'Set-Cookie' => $cookie->as_string );
+        Jifty->web->response->add_header(
+            'Set-Cookie' => $cookie->as_string );
     }
 }
 
-
 =head2 cookie_name
 
-Returns the current session's cookie_name. (It's a generic thing for all users
+Returns the current session's cookie_name -- it is the same for all
+users, but various accorting to the port the server is running on.
 
 =cut
 
@@ -262,25 +271,19 @@
     my $self = shift;
     my $cookiename = "JIFTY_SID_" . ( $ENV{'SERVER_PORT'} || 'NOPORT' );
     return ($cookiename);
-
 }
 
-=head2 expires
+=head2 expires [VALUE]
 
-Return this cache entry's expirey date, in the format expected by Cache::Cache;
+Get or set the session's expiration date, in a format expected by
+Cache::Cache.
 
 =cut
 
-
 sub expires {
-        my $self = shift;
-        if(@_) {
-                my $expiry = shift;
-        $self->set('_expires' => $expiry);
-    }
-        return ($self->get('_expires'));
+    my $self = shift;
+    $self->set( 'expires' => shift, "metadata" ) if @_;
+    return ( $self->get( 'expires', "metadata" ) );
 }
 
-
-
 1;


More information about the Jifty-commit mailing list