The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package WWW::TypePad::CmdLine;

use strict;
use 5.008_001;
our $VERSION = '0.02';

use Config::Tiny;
use File::HomeDir;
use File::Spec;
use Getopt::Long qw( :config pass_through );
use WWW::TypePad;

our $Config = File::Spec->catfile(
    File::HomeDir->my_data, '.www-typepad-info'
);
our $ConfigObj;

GetOptions( 'config=s' => \$Config );

sub config_file {
    my $class = shift;
    return $Config;
}

sub config {
    my $class = shift;
    return $ConfigObj ||= Config::Tiny->read( $class->config_file );
}

sub initialize {
    my $class = shift;
    my( %p ) = @_;

    my $tp;

    my $config = $class->config;
    if ( !defined $config && $p{requires_auth} ) {
        $tp = WWW::TypePad->new(
            ( $ENV{TP_HOST} ? ( host => $ENV{TP_HOST} ) : () ),
            consumer_key    => $ENV{TP_CONSUMER_KEY},
            consumer_secret => $ENV{TP_CONSUMER_SECRET},
        );

        die "TP_CONSUMER_KEY and TP_CONSUMER_SECRET required in ENV"
            unless $tp->consumer_key && $tp->consumer_secret;

        $class->new_config( $tp );
    } elsif ( $p{requires_auth} ) {
        $tp = WWW::TypePad->new(
            ( $config->{app}{host} ? ( host => $config->{app}{host} ) : () ),
            consumer_key        => $config->{app}{consumer_key},
            consumer_secret     => $config->{app}{consumer_secret},
            access_token        => $config->{auth}{access_token},
            access_token_secret => $config->{auth}{access_token_secret},
        );
    } else {
        $tp = WWW::TypePad->new;
    }

    return $tp;
}

sub new_config {
    my $class = shift;
    my( $tp ) = @_;

    $ConfigObj = Config::Tiny->new;

    print <<MSG;

Welcome to WWW::TypePad! Before we get started, we'll need to link our
local configuration to your TypePad account.

First, you'll need to authorize this application in your web browser.

MSG

    my $auth_uri = $tp->oauth->get_authorization_url(
        callback => 'oob',
    );

    if ( -x '/usr/bin/open' ) {
        print <<MSG;
We're opening this URL in your web browser:

$auth_uri
MSG
        system 'open', $auth_uri;
    } else {
        print <<MSG;
Open this URL in your web browser:

$auth_uri
MSG
    }

    print <<MSG;

When you've allowed access to this application, you'll get a verifier
code that we'll need to complete the handshake.

MSG

    print "Enter the verifier code: ";
    chomp( my $verifier = <STDIN> );
    
    my( $access_token, $access_token_secret ) =
        $tp->oauth->request_access_token( verifier => $verifier );
    $tp->access_token( $access_token );
    $tp->access_token_secret( $access_token_secret );
    
    my $obj = $tp->users->get( '@self' );
    die 'Request for @self gave us empty result'
        unless $obj;

    print <<MSG;

Great! We've identified you as "$obj->{displayName}".

We're going to save your configuration in the following file, in case you'd
like to access or change it in the future:

    $Config

MSG

    $ConfigObj->{app} = {
        ( $tp->host ne 'api.typepad.com' ? ( host => $tp->host ) : () ),
        consumer_key    => $tp->consumer_key,
        consumer_secret => $tp->consumer_secret,
    };

    $ConfigObj->{auth} = {
        access_token        => $access_token,
        access_token_secret => $access_token_secret,
    };

    $ConfigObj->write( $class->config_file );
}

1;
__END__

=encoding utf-8

=head1 NAME

WWW::TypePad::CmdLine - Helper library for writing WWW::TypePad apps

=head1 SYNOPSIS

    use WWW::TypePad::CmdLine;
    
    # Returns a WWW::TypePad instance, initialized with the necessary
    # consumer key/secret and access token/secret.
    my $tp = WWW::TypePad::CmdLine->initialize( requires_auth => 1 );

    # Then, you can do something like this:
    my $user = $tp->users->get( '@self' );

=head1 DESCRIPTION

I<WWW::TypePad::CmdLine> is a helper library for writing command-line
applications that use I<WWW::TypePad>. It handles the one-time OAuth
authentication flow, config file setup, and storage of access tokens.

Tokens and configuration are stored between runs of your application in
a config file. By default, that config file will be located at:

    File::Spec->catfile( File::HomeDir->my_data, '.www-typepad-info' )

I<File::HomeDir-E<gt>my_data> is an OS-aware data directory. On OS X, for
example, it's F<~/Library/Application Support>.

I<WWW::TypePad::CmdLine> automatically adds a C<--config> command-line
option for your application, so that it's easy to support different locations
for configuration files.

On the first execution of a script using I<WWW::TypePad::CmdLine>, you'll
need to set the C<TP_CONSUMER_KEY> and C<TP_CONSUMER_SECRET> environment
variables to the consumer key and secret for your TypePad application,
respectively. You can also set C<TP_HOST> to a host other than
C<api.typepad.com>. Once the configuration file is saved after the first
call to I<initialize>, future runs of your script won't require these
environment variables.

=head1 USAGE

=head2 WWW::TypePad::CmdLine->initialize( %param )

Initializes and returns a new I<WWW::TypePad> object, initialized with all
of the necessary information to start using it for authenticated requests
(see C<requires_auth>).

The configuration and tokens are stored between runs of your application in
a config file (see above). If the config file doesn't exist, and your
application requires authentication (see C<requires_auth>), I<initialize>
will send the user through the OAuth authentication flow.

When control returns to your application from calling I<initialize>, you'll
have a I<WWW::TypePad> object initialized with everything you need to make
authenticated (or non-authenticated) requests.

I<%param> can contain:

=over 4

=item * requires_auth

Controls whether or not your application requires an authenticated user
in order to function. This controls whether, in the absence of a configuration
file, I<initialize> will send the user through the OAuth authentication flow.

=back

=head1 AUTHOR

Benjamin Trott E<lt>ben@sixapart.comE<gt>

=head1 LICENSE

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=head1 SEE ALSO

L<WWW::TypePad>

=cut