#!/usr/bin/perl

# Script to get a web-based token that can be stored and
# used later to authorize our REST API access. 

# Based on code from https://gist.github.com/hexaddikt/6738162

# To use this script:
#
# 1. Read over https://stackoverflow.com/questions/11485271/google-oauth-2-authorization-error-redirect-uri-mismatch
#    It has a lot of useful background information.
#
# 2. Obtain a client_id and client_secret from your Google
#    Developer's console page.
#
# 3. Create a yaml file with the following format:
#
# ---
# auth:
#   class: OAuth2Client
#   client_id: <client-id-from-google>
#   client_secret: <client-secret-from-google>
#   token_file: <file-name-to-store-your-generated-token>
#
#    The token file will be stored in the same directory as
#    the config file.
#
#    Once this process is complete, this same config file
#    will be used by this package to access the Google API.
#
# 4. Run this script with the first arg pointing to the yaml
#    file above, and follow the directions on the screen,
#    which will take you through the following steps:
#
# 5. Copy the URL printed out, and paste the URL in a
#    browser to load the page. 
#
# 6. On the resulting page, click OK (possibly after being
#    asked to log in to your Google account). 
#
# 7. You will be redirected to a page that provides a string
#    that you should copy and paste back into the terminal
#    window, so this script can exchange it for an access
#    token from Google, and store the token. That wil be
#    the token for this package.

use FindBin;
use lib "$FindBin::RealBin/../lib";

use File::Basename;
use Storable;
use Term::Prompt;
use Type::Params qw(compile_named);
use Types::Standard qw(Str StrMatch);
use YAML::Any qw(Dump LoadFile);

use Google::RestApi::Auth::OAuth2Client;

# set the scope for the project you are working one.
# for this package, drive and spreadsheets are required.
my @scope = (
  'https://www.googleapis.com/auth/drive',
  'https://www.googleapis.com/auth/spreadsheets',
);

my $config_file = $ARGV[0];
my $config = LoadFile($config_file);
print "Config used:\n", Dump($config);

my $check = compile_named(
  class         => StrMatch[qr/^OAuth2Client$/],
  client_id     => Str,
  client_secret => Str,
  token_file    => Str,
);
$check->(%{ $config->{auth} });

my $oauth2 = Google::RestApi::Auth::OAuth2Client->new(
  client_id     => $config->{auth}->{client_id},
  client_secret => $config->{auth}->{client_secret},
  scope         => \@scope,
);

# We need to set these parameters this way in order to ensure 
# that we get not only an access token, but also a refresh token
# that can be used to update it as needed. 
my $url = $oauth2->authorize_url(
  access_type     => 'offline',
  approval_prompt => 'force',
);

# Give the user instructions on what to do:
print <<END

The following URL can be used to obtain an access token from
Google.  

1. Copy the URL and paste it into a browser.  

2. You may be asked to log into your Google account if you 
were not logged in already in that browser. If so, go 
ahead and log in to whatever account you want to have 
access to the Google doc. 

3. On the next page, click "Accept" when asked to grant access. 

4. You will then be redirected to a page with a box in the 
left-hand column labeled  "Authorization code". Copy the code 
in that box and come back here.

Here is the URL to paste in your browser to get the code:

$url

END
    ;

# Here is where we get the code from the user:
my $code = prompt('x', 'Paste the code obtained at the above URL here: ', '', ''); 

# Exchange the code for an access token:
my $token = $oauth2->access_token($code)
  or die "Unable to exchange the code for an access token";

# If we get to here, it worked!  Report success: 
print "\nToken obtained successfully!\n";
print "Here are the token contents:\n\n";
print $token->to_string(), "\n\n";

# Save the token for future use:
my $token_file = dirname($config_file) . "/$config->{auth}->{token_file}";
store($token->session_freeze(), $token_file);

print <<END2

Token successfully stored in file $token_file.

END2
    ;
