[Jifty-commit] r961 - in jifty/branches/jifty-jsan: . lib lib/Jifty/Action lib/Jifty/Model lib/Jifty/Script lib/Jifty/Test/WWW lib/Jifty/Upgrade lib/Jifty/Web t t/TestApp/t

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Sat Apr 29 12:57:35 EDT 2006


Author: trs
Date: Sat Apr 29 12:57:33 2006
New Revision: 961

Added:
   jifty/branches/jifty-jsan/lib/Jifty/Model/Metadata.pm
   jifty/branches/jifty-jsan/lib/Jifty/Upgrade/
   jifty/branches/jifty-jsan/lib/Jifty/Upgrade/Internal.pm
   jifty/branches/jifty-jsan/t/TestApp/t/04-sessions.t
Removed:
   jifty/branches/jifty-jsan/lib/Jifty/Model/Schema.pm
   jifty/branches/jifty-jsan/t/04-sessions.t
Modified:
   jifty/branches/jifty-jsan/   (props changed)
   jifty/branches/jifty-jsan/Makefile.PL
   jifty/branches/jifty-jsan/lib/Jifty.pm
   jifty/branches/jifty-jsan/lib/Jifty/Action/Record.pm
   jifty/branches/jifty-jsan/lib/Jifty/Everything.pm
   jifty/branches/jifty-jsan/lib/Jifty/Handle.pm
   jifty/branches/jifty-jsan/lib/Jifty/Model/Session.pm
   jifty/branches/jifty-jsan/lib/Jifty/Request.pm
   jifty/branches/jifty-jsan/lib/Jifty/Script/Schema.pm
   jifty/branches/jifty-jsan/lib/Jifty/Test.pm
   jifty/branches/jifty-jsan/lib/Jifty/Test/WWW/Mechanize.pm
   jifty/branches/jifty-jsan/lib/Jifty/Upgrade.pm
   jifty/branches/jifty-jsan/lib/Jifty/Web/Session.pm

Log:
 r10176 at zot (orig r951):  alexmv | 2006-04-28 02:06:35 -0400
  r12674 at zoq-fot-pik:  chmrr | 2006-04-28 01:59:48 -0400
   * Move session tests into TestApp, in preperation for them needing a database
 
 r10177 at zot (orig r952):  alexmv | 2006-04-28 02:06:43 -0400
  r12675 at zoq-fot-pik:  chmrr | 2006-04-28 02:01:16 -0400
   * Indent
 
 r10178 at zot (orig r953):  alexmv | 2006-04-28 02:06:53 -0400
  r12676 at zoq-fot-pik:  chmrr | 2006-04-28 02:01:51 -0400
   * Check if it can ->name before calling
 
 r10179 at zot (orig r954):  alexmv | 2006-04-28 02:07:02 -0400
  r12677 at zoq-fot-pik:  chmrr | 2006-04-28 02:03:32 -0400
   * Allow passing just a value, instead of having to specify the type
  (value, fallback, doublefallback)
 
 r10180 at zot (orig r955):  alexmv | 2006-04-28 15:49:53 -0400
  r12682 at zoq-fot-pik:  chmrr | 2006-04-28 15:48:33 -0400
   * _db_version -> _jifty_metadata, jifty schema versioning
 
 r10181 at zot (orig r956):  alexmv | 2006-04-28 15:49:59 -0400
  r12683 at zoq-fot-pik:  chmrr | 2006-04-28 15:49:31 -0400
   * Sessions stored in the database
 
 r10182 at zot (orig r957):  alexmv | 2006-04-28 16:05:43 -0400
  r12686 at zoq-fot-pik:  chmrr | 2006-04-28 16:05:27 -0400
   * POD nits
 
 r10183 at zot (orig r958):  alexmv | 2006-04-28 16:28:38 -0400
  r12688 at zoq-fot-pik:  chmrr | 2006-04-28 16:28:22 -0400
   * Class 'load' and 'store' methods always act as the superuser
 
 r10184 at zot (orig r959):  alexmv | 2006-04-28 17:04:39 -0400
  r12690 at zoq-fot-pik:  chmrr | 2006-04-28 17:04:20 -0400
   * Bump DBD::SQLite dependency to 1.11, which supports blobs transparently
 
 r10185 at zot (orig r960):  alexmv | 2006-04-28 17:48:13 -0400
  r12692 at zoq-fot-pik:  chmrr | 2006-04-28 17:47:58 -0400
   * Typxo caught by Bart Bunting <bart at bunting.net.au>
 


Modified: jifty/branches/jifty-jsan/Makefile.PL
==============================================================================
--- jifty/branches/jifty-jsan/Makefile.PL	(original)
+++ jifty/branches/jifty-jsan/Makefile.PL	Sat Apr 29 12:57:33 2006
@@ -11,7 +11,7 @@
 requires('Class::Container');
 requires('Clone');
 requires('Compress::Zlib');
-requires('DBD::SQLite');
+requires('DBD::SQLite' => 1.11 );
 requires('Data::Page');
 requires('DateTime');
 requires('Date::Manip');

Modified: jifty/branches/jifty-jsan/lib/Jifty.pm
==============================================================================
--- jifty/branches/jifty-jsan/lib/Jifty.pm	(original)
+++ jifty/branches/jifty-jsan/lib/Jifty.pm	Sat Apr 29 12:57:33 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.60321';
+our $VERSION = '0.60428';
 
 =head1 NAME
 

Modified: jifty/branches/jifty-jsan/lib/Jifty/Action/Record.pm
==============================================================================
--- jifty/branches/jifty-jsan/lib/Jifty/Action/Record.pm	(original)
+++ jifty/branches/jifty-jsan/lib/Jifty/Action/Record.pm	Sat Apr 29 12:57:33 2006
@@ -163,7 +163,7 @@
 
           # XXX This assumes a ->name and a ->id method
           $info->{valid_values} = [
-            { display_from => 'name',
+            { display_from => $refers_to->can('name') ? "name" : "id",
               value_from   => 'id',
               collection   => $collection
             }

Modified: jifty/branches/jifty-jsan/lib/Jifty/Everything.pm
==============================================================================
--- jifty/branches/jifty-jsan/lib/Jifty/Everything.pm	(original)
+++ jifty/branches/jifty-jsan/lib/Jifty/Everything.pm	Sat Apr 29 12:57:33 2006
@@ -37,8 +37,8 @@
 use Jifty::View::Static::Handler ();
 use Jifty::View::Mason::Handler ();
 
-use Jifty::Model::Schema ();
-
+use Jifty::Model::Metadata ();
+use Jifty::Model::Session ();
 
 
 use Jifty::Request ();

Modified: jifty/branches/jifty-jsan/lib/Jifty/Handle.pm
==============================================================================
--- jifty/branches/jifty-jsan/lib/Jifty/Handle.pm	(original)
+++ jifty/branches/jifty-jsan/lib/Jifty/Handle.pm	Sat Apr 29 12:57:33 2006
@@ -101,18 +101,50 @@
 =cut
 
 sub check_schema_version {
-    my $appv
-        = version->new( Jifty->config->framework('Database')->{'Version'} );
-    require Jifty::Model::Schema;
-    my $dbv = Jifty::Model::Schema->new->in_db;
-    die
-        "Schema has no version in the database; perhaps you need to run this:\n\t bin/jifty schema --setup\n"
-        unless defined $dbv;
-
-    die
-        "Schema version in database ($dbv) doesn't match application schema version ($appv)\n"
-        . "Please run `bin/jifty schema --setup` to upgrade the database.\n"
-        unless $appv == $dbv;
+    require Jifty::Model::Metadata;
+
+    # Application db version check
+    {
+        my $dbv  = Jifty::Model::Metadata->load("application_db_version");
+        my $appv = Jifty->config->framework('Database')->{'Version'};
+
+        # Backwards compatibility -- it used to be in _db_version
+        if ( not defined $dbv ) {
+            my @v;
+            eval {
+                local $SIG{__WARN__} = sub { };
+                @v = Jifty->handle->fetch_result(
+                    "SELECT major, minor, rev FROM _db_version");
+            };
+            $dbv = join( ".", @v ) if @v == 3;
+        }
+
+        die
+            "Application schema has no version in the database; perhaps you need to run this:\n"
+            . "\t bin/jifty schema --setup\n"
+            unless defined $dbv;
+
+        die
+            "Application schema version in database ($dbv) doesn't match application schema version ($appv)\n"
+            . "Please run `bin/jifty schema --setup` to upgrade the database.\n"
+            unless version->new($appv) == version->new($dbv);
+    }
+
+    # Jifty db version check
+    {
+
+        # If we got here, the application had a version (somehow) so
+        # this is an upgrade.  If $dbv is undef, it's because it's
+        # from before when the _jifty_metadata table existed.
+        my $dbv
+            = version->new( Jifty::Model::Metadata->load("jifty_db_version")
+                || '0.60426' );
+        my $appv = version->new($Jifty::VERSION);
+        die
+            "Internal jifty schema version in database ($dbv) doesn't match running jifty version ($appv)\n"
+            . "Please run `bin/jifty schema --setup` to upgrade the database.\n"
+            unless $appv == $dbv;
+    }
 
 }
 

Added: jifty/branches/jifty-jsan/lib/Jifty/Model/Metadata.pm
==============================================================================
--- (empty file)
+++ jifty/branches/jifty-jsan/lib/Jifty/Model/Metadata.pm	Sat Apr 29 12:57:33 2006
@@ -0,0 +1,96 @@
+use warnings;
+use strict;
+
+=head1 NAME
+
+Jifty::Model::Metadata - Tracks Jifty-related metadata
+
+=head1 SYNOPSIS
+
+  my $app = Jifty->new(config_file => "$ProjectRoot/etc/config.yml");
+  my $application_version = Jifty::Model::Metadata->load("application_db_version");
+
+=head1 DESCRIPTION
+
+Every Jifty application automatically inherits this table, which
+describes information about the Jifty database.  It uses this
+information to smartly upgrade between application versions, as well
+as versions of Jifty itself, for instance.
+
+=cut
+
+package Jifty::Model::Metadata::Schema;
+use Jifty::DBI::Schema;
+
+column key   => type is 'text';
+column value => type is 'text';
+
+package Jifty::Model::Metadata;
+use version;
+
+use base qw( Jifty::Record );
+
+=head2 table
+
+Schemas are stored in the table C<_jifty_metadata>.
+
+=cut
+
+sub table {'_jifty_metadata'}
+
+=head2 since
+
+The metadata table first appeared in Jifty version 0.60427
+
+=cut
+
+sub since {'0.60427'}
+
+=head2 load KEY
+
+Fetches the given C<KEY> from the metadata store.  Returns undef if
+such a key cannot be found.
+
+=cut
+
+sub load {
+    my $self = shift;
+    $self = $self->new( current_user => Jifty::CurrentUser->superuser )
+        unless ref $self;
+    return undef unless $self->_handle and $self->_handle->dbh->ping;
+
+    my ($key) = @_;
+
+    # This may barf all over the place.  That's almost expected in
+    # some circumstances, so we eat all warnings and errors right
+    # here, right now.
+    eval {
+        local $SIG{__WARN__} = sub { };
+        $self->load_by_cols( key => $key );
+    };
+    return undef unless $self->id;
+    return $self->value;
+}
+
+=head2 store KEY => VALUE
+
+Stores the given C<KEY> in the database, overwriting the previous
+value if it existed.
+
+=cut
+
+sub store {
+    my $self = shift;
+    $self = $self->new( current_user => Jifty::CurrentUser->superuser )
+        unless ref $self;
+
+    my ( $key, $value ) = @_;
+    $self->load_by_cols( key => $key );
+    if ( $self->id ) {
+        $self->set_value($value);
+    } else {
+        $self->create( key => $key, value => $value );
+    }
+}
+
+1;

Modified: jifty/branches/jifty-jsan/lib/Jifty/Model/Session.pm
==============================================================================
--- jifty/branches/jifty-jsan/lib/Jifty/Model/Session.pm	(original)
+++ jifty/branches/jifty-jsan/lib/Jifty/Model/Session.pm	Sat Apr 29 12:57:33 2006
@@ -1,2 +1,109 @@
-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'}
+
+=head2 since
+
+Sessions first started getting stored in the database in Jifty version
+0.60428
+
+=cut
+
+sub since { '0.60428' }
+
+=head2 current_user
+
+Everyone is treated as the superuser when dealing with session
+objects.  This avoids infinite recursion, as otherwise it would try to
+look up the current user in the session object to find out who we
+are...
+
+=cut
+
+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/branches/jifty-jsan/lib/Jifty/Request.pm
==============================================================================
--- jifty/branches/jifty-jsan/lib/Jifty/Request.pm	(original)
+++ jifty/branches/jifty-jsan/lib/Jifty/Request.pm	Sat Apr 29 12:57:33 2006
@@ -138,9 +138,13 @@
     for my $a (values %actions) {
         my %arguments;
         for my $arg (keys %{$a->{fields} || {}}) {
-            for my $type (qw/doublefallback fallback value/) {
-                $arguments{$arg} = $a->{fields}{$arg}{$type}
-                  if exists $a->{fields}{$arg}{$type};
+            if (ref $a->{fields}{$arg}) {
+                for my $type (qw/doublefallback fallback value/) {
+                    $arguments{$arg} = $a->{fields}{$arg}{$type}
+                      if exists $a->{fields}{$arg}{$type};
+                }
+            } else {
+                $arguments{$arg} = $a->{fields}{$arg};
             }
         }
         $self->add_action(moniker   => $a->{moniker},

Modified: jifty/branches/jifty-jsan/lib/Jifty/Script/Schema.pm
==============================================================================
--- jifty/branches/jifty-jsan/lib/Jifty/Script/Schema.pm	(original)
+++ jifty/branches/jifty-jsan/lib/Jifty/Script/Schema.pm	Sat Apr 29 12:57:33 2006
@@ -48,7 +48,8 @@
     if ( $self->{create_all_tables} ) {
         $self->create_all_tables();
     } elsif ( $self->{'setup_tables'} ) {
-        $self->upgrade_tables();
+        $self->upgrade_jifty_tables();
+        $self->upgrade_appliction_tables();
     } else {
         print "Done.\n";
     }
@@ -66,7 +67,7 @@
 
     # Import Jifty
     Jifty::Util->require("Jifty");
-    Jifty::Util->require("Jifty::Model::Schema");
+    Jifty::Util->require("Jifty::Model::Metadata");
 }
 
 
@@ -143,7 +144,7 @@
             logger_component => 'SchemaTool',
         );
     };
-    if ( $@ =~ /doesn't match application schema version/i ) {
+    if ( $@ =~ /doesn't match (application schema|running jifty) version/i) {
         # We found an out-of-date DB.  Upgrade it
         $self->{setup_tables} = 1;
     } elsif ( $@ =~ /no version in the database/i ) {
@@ -179,13 +180,14 @@
 sub create_all_tables {
     my $self = shift;
 
-    my $schema = Jifty::Model::Schema->new;
     my $log    = Log::Log4perl->get_logger("SchemaTool");
     $log->info(
         "Generating SQL for application $self->{'_application_class'}...");
 
     my $appv
         = version->new( Jifty->config->framework('Database')->{'Version'} );
+    my $jiftyv
+        = version->new( $Jifty::VERSION || '0.60426' );
 
     for my $model ( __PACKAGE__->models ) {
 
@@ -196,9 +198,9 @@
        #   This *will* try to generate SQL for abstract base classes you might
        #   stick in $AC::Model::.
         next unless $model->isa( 'Jifty::Record' );
-        do { log->info("Skipping $model"); next }
+        do { $log->info("Skipping $model"); next }
             if ( $model->can( 'since' )
-            and $appv < $model->since );
+            and ($model =~ /^Jifty::Model::/ ? $jiftyv : $appv) < $model->since );
 
         $log->info("Using $model");
         my $ret = $self->{'_schema_generator'}->add_model( $model->new );
@@ -219,8 +221,9 @@
             $ret or die "error creating a table: " . $ret->error_message;
         }
 
-        # Update the version in the database
-        $schema->update($appv);
+        # Update the versions in the database
+        Jifty::Model::Metadata->store( application_db_version => $appv);
+        Jifty::Model::Metadata->store( jifty_db_version => $jiftyv);
 
         # Load initial data
         eval {
@@ -235,52 +238,79 @@
         # Commit it all
         Jifty->handle->commit;
     }
-    $log->info("Set up version $appv");
+    $log->info("Set up version $appv, jifty version $jiftyv");
 }
 
 
-=head2 upgrade_tables 
+=head2 upgrade_jifty_tables
 
-Upgrade your app's tables to match your current model.
+Upgrade Jifty's internal tables.
+
+=cut
+
+sub upgrade_jifty_tables {
+    my $self = shift;
+    my $dbv  = version->new( Jifty::Model::Metadata->load( 'jifty_db_version' ) || '0.60426' );
+    my $appv = version->new( $Jifty::VERSION );
+
+    $self->upgrade_tables( "Jifty" => $dbv, $appv, "Jifty::Upgrade::Internal" );
+    Jifty::Model::Metadata->store( jifty_db_version => $appv );
+}
+
+=head2 upgrade_appliction_tables
+
+Upgrade the application's tables.
+
+=cut
+
+sub upgrade_appliction_tables {
+    my $self = shift;
+    my $dbv = version->new( Jifty::Model::Metadata->load( 'application_db_version' ) );
+    my $appv
+        = version->new( Jifty->config->framework('Database')->{'Version'} );
+
+    $self->upgrade_tables( $self->{_application_class} => $dbv, $appv );
+    Jifty::Model::Metadata->store( application_db_version => $appv );
+}
+
+=head2 upgrade_tables BASECLASS, FROM, TO, [UPGRADECLASS]
+
+Given a C<BASECLASS> to upgrade, and two L<version> objects, C<FROM>
+and C<TO>, performs the needed transforms to the database.
+C<UPGRADECLASS>, if not specified, defaults to C<BASECLASS>::Upgrade
 
 =cut
 
 sub upgrade_tables {
     my $self = shift;
+    my ($baseclass, $dbv, $appv, $upgradeclass ) = @_;
+    $upgradeclass ||= $baseclass."::Upgrade";
 
-    my $schema = Jifty::Model::Schema->new;
     my $log    = Log::Log4perl->get_logger("SchemaTool");
     # Find current versions
-    my $dbv = $schema->in_db;
-    my $appv
-        = version->new( Jifty->config->framework('Database')->{'Version'} );
 
     if ( $appv < $dbv ) {
-        print "Version $appv from module older than $dbv in database!\n";
-        exit;
+        print "$baseclass version $appv from module older than $dbv in database!\n";
+        return;
     } elsif ( $appv == $dbv ) {
-
         # Shouldn't happen
-        print "Version $appv up to date.\n";
-        exit;
+        print "$baseclass version $appv up to date.\n";
+        return;
     }
     $log->info(
-        "Gerating SQL to update $self->{'_application_class'} $dbv database to $appv"
+        "Gerating SQL to upgrade $baseclass $dbv database to $appv"
     );
 
-    my %UPGRADES;
-
     # Figure out what versions the upgrade knows about.
+    my %UPGRADES;
     eval {
-        my $upgrader = $self->{'_application_class'} . "::Upgrade";
-        Jifty::Util->require($upgrader);
-
-        $UPGRADES{$_} = [ $upgrader->upgrade_to($_) ]
+        Jifty::Util->require($upgradeclass);
+        $UPGRADES{$_} = [ $upgradeclass->upgrade_to($_) ]
             for grep { $appv >= version->new($_) and $dbv < version->new($_) }
-            $upgrader->versions();
+            $upgradeclass->versions();
     };
 
-    for my $model ( __PACKAGE__->models ) {
+    for my $model ( grep {/^\Q$baseclass\E::Model::/} __PACKAGE__->models ) {
 
         # We don't want to get the Collections, for example.
         do {next} unless $model->isa( 'Jifty::Record' );
@@ -372,7 +402,6 @@
                 }
             }
         }
-        $schema->update($appv);
         $log->info("Upgraded to version $appv");
         Jifty->handle->commit;
     }

Modified: jifty/branches/jifty-jsan/lib/Jifty/Test.pm
==============================================================================
--- jifty/branches/jifty-jsan/lib/Jifty/Test.pm	(original)
+++ jifty/branches/jifty-jsan/lib/Jifty/Test.pm	Sat Apr 29 12:57:33 2006
@@ -183,12 +183,12 @@
 
         # Remove testing db
         if (Jifty->handle) {
-        Jifty->handle->disconnect();
-        Log::Log4perl->get_logger("SchemaTool")->less_logging(3);
-        my $schema = Jifty::Script::Schema->new;
-        $schema->{drop_database} = 1;
-        $schema->run;
-        Log::Log4perl->get_logger("SchemaTool")->more_logging(3);
+            Jifty->handle->disconnect();
+            Log::Log4perl->get_logger("SchemaTool")->less_logging(3);
+            my $schema = Jifty::Script::Schema->new;
+            $schema->{drop_database} = 1;
+            $schema->run;
+            Log::Log4perl->get_logger("SchemaTool")->more_logging(3);
         }
     }
 }

Modified: jifty/branches/jifty-jsan/lib/Jifty/Test/WWW/Mechanize.pm
==============================================================================
--- jifty/branches/jifty-jsan/lib/Jifty/Test/WWW/Mechanize.pm	(original)
+++ jifty/branches/jifty-jsan/lib/Jifty/Test/WWW/Mechanize.pm	Sat Apr 29 12:57:33 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/branches/jifty-jsan/lib/Jifty/Upgrade.pm
==============================================================================
--- jifty/branches/jifty-jsan/lib/Jifty/Upgrade.pm	(original)
+++ jifty/branches/jifty-jsan/lib/Jifty/Upgrade.pm	Sat Apr 29 12:57:33 2006
@@ -28,13 +28,14 @@
 
 =cut
 
-sub since { 
-  my ($version, $sub) = @_;
-  if (exists $UPGRADES{$version}) {
-    $UPGRADES{$version} = sub { $UPGRADES{$version}->(); $sub->(); }
-  } else {
-    $UPGRADES{$version} = $sub;
-  }
+sub since {
+    my ($version, $sub) = @_;
+    my $package = (caller)[0];
+    if (exists $UPGRADES{$package}{$version}) {
+        $UPGRADES{$package}{$version} = sub { $UPGRADES{$package}{$version}->(); $sub->(); }
+    } else {
+        $UPGRADES{$package}{$version} = $sub;
+    }
 }
 
 =head2 versions
@@ -46,7 +47,8 @@
 =cut
 
 sub versions {
-  return sort keys %UPGRADES;
+    my $class = shift;
+    return sort keys %{$UPGRADES{$class} || {}};
 }
 
 =head2 upgrade_to I<VERSION>
@@ -57,9 +59,9 @@
 =cut
 
 sub upgrade_to {
-  my $self = shift;
+  my $class = shift;
   my $version = shift;
-  return $UPGRADES{$version} || sub {};
+  return $UPGRADES{$class}{$version} || sub {};
 }
 
 1;

Added: jifty/branches/jifty-jsan/lib/Jifty/Upgrade/Internal.pm
==============================================================================
--- (empty file)
+++ jifty/branches/jifty-jsan/lib/Jifty/Upgrade/Internal.pm	Sat Apr 29 12:57:33 2006
@@ -0,0 +1,23 @@
+use strict;
+use warnings;
+
+package Jifty::Upgrade::Internal;
+use Jifty::Upgrade;
+use base qw/Jifty::Upgrade/;
+use Jifty::Model::Metadata;
+
+=head2 Version 0.60427
+
+Version metadata, previously stored in _db_version, get migrated to
+_jifty_metadata, so it could be used to store more than one row
+usefully.
+
+=cut
+
+since '0.60427' => sub {
+    my @v = Jifty->handle->fetch_result("SELECT major, minor, rev FROM _db_version");
+    Jifty->handle->simple_query("DROP TABLE _db_version");
+    Jifty::Model::Metadata->store( application_db_version => version->new(join'.', at v));
+};
+
+1;

Modified: jifty/branches/jifty-jsan/lib/Jifty/Web/Session.pm
==============================================================================
--- jifty/branches/jifty-jsan/lib/Jifty/Web/Session.pm	(original)
+++ jifty/branches/jifty-jsan/lib/Jifty/Web/Session.pm	Sat Apr 29 12:57:33 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
+=head2 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;

Added: jifty/branches/jifty-jsan/t/TestApp/t/04-sessions.t
==============================================================================
--- (empty file)
+++ jifty/branches/jifty-jsan/t/TestApp/t/04-sessions.t	Sat Apr 29 12:57:33 2006
@@ -0,0 +1,37 @@
+#!/usr/bin/perl 
+
+use warnings;
+use strict;
+
+BEGIN {chdir "t/TestApp"}
+use lib '../../lib';
+use Jifty::Test tests => 11;
+
+use_ok('Jifty');
+Jifty->new();
+
+use_ok('Jifty::Web::Session');
+
+my $s = Jifty::Web::Session->new();
+
+isa_ok($s,'Jifty::Web::Session');
+
+$s->load();
+ok($s->loaded);
+is($s->get('foo'), undef);
+$s->set( foo => 'bar');
+is($s->get('foo'), 'bar');
+
+my $id = $s->id;
+$s->unload;
+ok(!$s->loaded);
+
+$s->load();
+ok($s->loaded);
+isnt($s->id, $id);
+is($s->get('foo'), undef);
+
+$s->load($id);
+is($s->get('foo'), 'bar');
+
+1;


More information about the Jifty-commit mailing list