* Plugins and actions need to work better
* Plugins should be able to create model classes
* So should applications
* Plugins can add columns to model classes
* Plugins can add logic to model classes (before_*, after_* hooks)
* Plugins should be able to add properties to columns
* The app always overrides plugins
* Plugins are loaded and evaluated in order
* Models should become mixins when appropriate
  - But if the app doesn't define one, they can create classes/tables #'


The plugins we want in our ponyverse:
* ::Users
* ::Users::Identity::EmailedToken
*                  ::UsernamePassword
*                  ::OpenID
*                  ::Certs
*                  ::{Assertion,Kerberos,...}
*        ::ResetIdentity (change password for any identity once logged in / add identity)
* ::Users::Signup
* ::Users::Login
* ::Users::EmailAddress

::Users
* unique ID
* created_date, update_date, created_by, updated_by
* display_name field (which you can force to something -- e.g. email, openid, name from cert)
 * (Jifty::Record _brief_description returns this?)
* last_login (?)
* Do superuser and nobody live in the database? (That's authz)

Where do identity plugins hook?
* Add columns
* Get credentials, return:
    * These are valid
    * These are invalid
    * Other auth error ``I don't know''
  * bounce trips go through continuations
* load_by_unique_id

* ::Login
* /login =>
  * list of identity types
   * for each, fields for login columns declared by the ::Identity::Foo plugin
  * submit button
* Login action
  * load_by_unique_id
  * if the user doesn't exist, callback (to signup) or error
  * Passes credentials to the identity plugin's auth method
   * Identities that need confirmation error here if needed
  * frob the session as appropriate
  * frob CurrentUser
  * Adds Dispatcher variables
* Logout action
  * frob the session and current user
  * dispatcher rule on /logout redirects

* ::Signup
* Signup action
  * verifies credentials - validates fields (inc. uniqueness)
  * Creates a record
  * Add a message, and push the user to the login page with a filled-out login action

* What do ``mixins'' *mean*?
 * We want injection, not actual mixins


----- Where is this going to be hard? -----
* Mixing columns into users
* Getting the autogenerated actions to DTRT
* hooks look kinda like Plagger
* If there are multiple plugin models with no app model,
  they all get mixed into the null model


----- Username/password plugin ------

# Model (Jifty::Plugin::User::Identity::UsernamePassword::Model::User)

column 'username' =>
  type is 'text',
  is unique;

column 'password' =>
  type is 'text',
  render_as 'Password',
  filters are qw(Jifty::DBI::Filter::SaltHash);

sub password_is {
    my $self = shift;
    my $pass = shift;

    return undef unless $self->_value('password');

    my ($hash, $salt) = @{$self->_value('password')};

    return 1 if ( $hash eq Digest::MD5::md5_hex($pass . $salt) );
    return undef;

}

# ``exports''
sub load_by_unique_id {
    my $self = shift;
    my %args = (username => undef, @_);
    return $self->load_by_columns(username => $args{username});
}

sub validate_credentials {
    my $self = shift;
    my %args = (username => undef, @_);
    return unless $self->id;
    return $self->password_is($args{password});
}

# Jifty::Plugin::User::Identity::UsernamePassword::Action::Login

param username =>
  render_as 'Text';

param password =>
  render_as 'Password';



# Login plugin Action::Login
sub check_credentials {
    my $self = shift;
    my $userobj = MyApp::Model::User->new;
    my $user;
    foreach my $identity_type ($userobj->identity_plugins) {
        if($userobj->($identity_type . "::load_by_unique_id")($self->argument_values)) {
            if($userobj->($identity_type . "::validate_credentials")($self->argument_values)) {
                ...
            } else {
                ...
            }
        }
    }
}