[Jifty-commit] r4526 - in Net-Jifty: .

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Wed Nov 21 16:18:13 EST 2007


Author: sartak
Date: Wed Nov 21 16:18:13 2007
New Revision: 4526

Modified:
   Net-Jifty/   (props changed)
   Net-Jifty/Makefile.PL
   Net-Jifty/lib/Net/Jifty.pm

Log:
 r45502 at onn:  sartak | 2007-11-21 16:17:53 -0500
 Add todo.pl-like config handling to Net::Jifty. cool.


Modified: Net-Jifty/Makefile.PL
==============================================================================
--- Net-Jifty/Makefile.PL	(original)
+++ Net-Jifty/Makefile.PL	Wed Nov 21 16:18:13 2007
@@ -10,6 +10,7 @@
 requires        'Encode';
 requires        'DateTime';
 requires        'Email::Address';
+requires        'Term::ReadKey';
 
 build_requires  'Test::More';
 build_requires  'Test::MockObject';

Modified: Net-Jifty/lib/Net/Jifty.pm
==============================================================================
--- Net-Jifty/lib/Net/Jifty.pm	(original)
+++ Net-Jifty/lib/Net/Jifty.pm	Wed Nov 21 16:18:13 2007
@@ -7,6 +7,7 @@
 use LWP::UserAgent;
 use DateTime;
 use Email::Address;
+use Fcntl qw(:mode);
 
 =head1 NAME
 
@@ -47,21 +48,21 @@
 =cut
 
 has site => (
-    is            => 'ro',
+    is            => 'rw',
     isa           => 'Str',
     required      => 1,
     documentation => "The URL of your application",
 );
 
 has cookie_name => (
-    is            => 'ro',
+    is            => 'rw',
     isa           => 'Str',
     required      => 1,
     documentation => "The name of the session ID cookie. This can be found in your config under Framework/Web/SessinCookieName",
 );
 
 has appname => (
-    is            => 'ro',
+    is            => 'rw',
     isa           => 'Str',
     required      => 1,
     documentation => "The name of the application, as it is known to Jifty",
@@ -111,9 +112,33 @@
     },
 );
 
+has config_file => (
+    is            => 'rw',
+    isa           => 'Str',
+    default       => "$ENV{HOME}/.jifty",
+    documentation => "The place to look for the user's config file",
+);
+
+has use_config => (
+    is      => 'rw',
+    isa     => 'Bool',
+    default => 0,
+    documentation => "Whether or not to use the user's config",
+);
+
+has config => (
+    is      => 'rw',
+    isa     => 'HashRef',
+    default => sub { {} },
+    documentation => "Storage for the user's config",
+);
+
 sub BUILD {
     my $self = shift;
 
+    $self->load_config
+        if $self->use_config && $self->config_file;
+
     $self->login
         unless $self->sid;
 }
@@ -123,6 +148,9 @@
 This assumes your site is using L<Jifty::Plugin::Authentication::Password>.
 If that's not the case, override this in your subclass.
 
+This is called automatically when each L<Net::Jifty> object is constructed
+(unless a session ID is passed in).
+
 =cut
 
 sub login {
@@ -144,6 +172,7 @@
         if $result->{failure};
 
     $self->get_sid;
+    return 1;
 }
 
 =head2 call Action, Args
@@ -479,6 +508,173 @@
     return $self->email_eq($self->email, $email);
 }
 
+=head2 load_config
+
+This will return a hash reference of the user's preferences. Because this
+method is designed for use in small standalone scripts, it has a few
+peculiarities.
+
+=over 4
+
+=item
+
+It will C<warn> if the permissions are too liberal on the config file, and fix
+them.
+
+=item
+
+It will prompt the user for an email and password if necessary. Given
+the email and password, it will attempt to log in using them. If that fails,
+then it will try again.
+
+=item
+
+Upon successful login, it will write a new config consisting of the options
+already in the config plus session ID, email, and password.
+
+=back
+
+=cut
+
+sub load_config {
+    my $self = shift;
+
+    $self->config_permissions;
+    $self->read_config_file;
+
+    # allow config to override everything. this may need to be less free in
+    # the future
+    while (my ($key, $value) = each %{ $self->config }) {
+        $self->$key($value)
+            if $self->can($key);
+    }
+
+    $self->prompt_login_info
+        unless $self->config->{email} || $self->config->{sid};
+
+    # update config if we are logging in manually
+    unless ($self->config->{sid}) {
+
+        # if we have user/pass in the config then we still need to log in here
+        unless ($self->sid) {
+            $self->login;
+        }
+
+        # now write the new config
+        $self->config->{sid} = $self->sid;
+        $self->write_config_file;
+    }
+
+    return $self->config;
+}
+
+=head2 config_permissions
+
+This will warn about (and fix) config files being readable by group or others.
+
+=cut
+
+sub config_permissions {
+    my $self = shift;
+    my $file = $self->config_file;
+
+    return if $^O eq 'MSWin32';
+    return unless -e $file;
+    my @stat = stat($file);
+    my $mode = $stat[2];
+    if ($mode & S_IRGRP || $mode & S_IROTH) {
+        warn "Config file $file is readable by users other than you, fixing.";
+        chmod 0600, $file;
+    }
+}
+
+=head2 read_config_file
+
+This transforms the config file to a hashref. It also does any postprocessing
+needed, such as transforming localhost to 127.0.0.1 (due to an obscure bug,
+probably in HTTP::Cookies)
+
+=cut
+
+sub read_config_file {
+    my $self = shift;
+    my $file = $self->config_file;
+
+    return unless -e $file;
+
+    $self->config(YAML::LoadFile($self->config_file) || {});
+
+    if ($self->config->{site}) {
+        # Somehow, localhost gets normalized to localhost.localdomain,
+        # and messes up HTTP::Cookies when we try to set cookies on
+        # localhost, since it doesn't send them to
+        # localhost.localdomain.
+        $self->config->{site} =~ s/localhost/127.0.0.1/;
+    }
+}
+
+=head2 write_config_file
+
+This will write the config to disk. This is usually only done when a sid is
+discovered, but may happen any time.
+
+=cut
+
+sub write_config_file {
+    my $self = shift;
+    my $file = $self->config_file;
+
+    YAML::DumpFile($file, $self->config);
+    chmod 0600, $file;
+}
+
+=head2 prompt_login_info
+
+This will ask the user for her email and password. It may do so repeatedly
+until login is successful.
+
+=cut
+
+sub prompt_login_info {
+    my $self = shift;
+
+    print << "END_WELCOME";
+Before we get started, please enter your @{[ $self->site ]}
+username and password.
+
+This information will be stored in @{[ $self->config_file ]}, 
+should you ever need to change it.
+
+END_WELCOME
+
+    local $| = 1; # Flush buffers immediately
+
+    while (1) {
+        print "First, what's your email address? ";
+        $self->config->{email} = <STDIN>;
+        chomp($self->config->{email});
+
+        require Term::ReadKey;
+        print "And your password? ";
+        Term::ReadKey::ReadMode('noecho');
+        $self->config->{password} = <STDIN>;
+        chomp($self->config->{password});
+        Term::ReadKey::ReadMode('restore');
+
+        print "\n";
+
+        $self->email($self->config->{email});
+        $self->password($self->config->{password});
+
+        last if eval { $self->login };
+
+        $self->email('');
+        $self->password('');
+
+        print "That combination doesn't seem to be correct. Try again?\n";
+    }
+}
+
 =head1 SEE ALSO
 
 L<Jifty>, L<Net::Hiveminder>


More information about the Jifty-commit mailing list