From 37df3760ab4de8090fd56ed421bad9231e346186 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Thu, 26 Mar 2015 02:03:30 -0400 Subject: initial implementation --- bin/pocket | 6 +++ lib/WWW/Pocket.pm | 119 +++++++++++++++++++++++++++++++++++++++++++ lib/WWW/Pocket/Script.pm | 130 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 255 insertions(+) create mode 100644 bin/pocket create mode 100644 lib/WWW/Pocket/Script.pm diff --git a/bin/pocket b/bin/pocket new file mode 100644 index 0000000..c38d497 --- /dev/null +++ b/bin/pocket @@ -0,0 +1,6 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use WWW::Pocket::Script; +WWW::Pocket::Script->new_with_options->run; diff --git a/lib/WWW/Pocket.pm b/lib/WWW/Pocket.pm index e69de29..20da851 100644 --- a/lib/WWW/Pocket.pm +++ b/lib/WWW/Pocket.pm @@ -0,0 +1,119 @@ +package WWW::Pocket; +use Moose; + +use HTTP::Tiny; +use JSON::PP; + +has consumer_key => ( + is => 'rw', + isa => 'Str', +); + +has access_token => ( + is => 'rw', + isa => 'Str', +); + +has username => ( + is => 'rw', + isa => 'Str', +); + +has base_uri => ( + is => 'ro', + isa => 'Str', + default => 'https://getpocket.com/v3/', +); + +has ua => ( + is => 'ro', + isa => 'HTTP::Tiny', + lazy => 1, + default => sub { HTTP::Tiny->new }, +); + +sub start_authentication { + my $self = shift; + my ($consumer_key, $redirect_uri) = @_; + + return if $self->consumer_key && $self->access_token; + + $redirect_uri ||= 'https://getpocket.com/'; + + my $response = $self->_request( + $self->base_uri . 'oauth/request', + { + consumer_key => $consumer_key, + redirect_uri => $redirect_uri, + }, + ); + return $response->{code}; +} + +sub finish_authentication { + my $self = shift; + my ($consumer_key, $code) = @_; + + my $response = $self->_request( + $self->base_uri . 'oauth/authorize', + { + consumer_key => $consumer_key, + code => $code, + }, + ); + + $self->consumer_key($consumer_key); + $self->access_token($response->{access_token}); + $self->username($response->{username}); +} + +sub add { + my $self = shift; + my (%params) = @_; + return $self->_endpoint_request('add', \%params); +} + +sub modify { + my $self = shift; + my (%params) = @_; + return $self->_endpoint_request('send', \%params); +} + +sub retrieve { + my $self = shift; + my (%params) = @_; + return $self->_endpoint_request('get', \%params); +} + +sub _endpoint_request { + my $self = shift; + my ($endpoint, $params) = @_; + $params->{consumer_key} = $self->consumer_key; + $params->{access_token} = $self->access_token; + return $self->_request($self->base_uri . $endpoint, $params); +} + +sub _request { + my $self = shift; + my ($uri, $params) = @_; + + my $response = $self->ua->post( + $uri, + { + content => encode_json($params), + headers => { + 'Content-Type' => 'application/json; charset=UTF-8', + 'X-Accept' => 'application/json', + }, + }, + ); + die "Request for $uri failed ($response->{status}): $response->{reason}" + unless $response->{success}; + + return decode_json($response->{content}); +} + +__PACKAGE__->meta->make_immutable; +no Moose; + +1; diff --git a/lib/WWW/Pocket/Script.pm b/lib/WWW/Pocket/Script.pm new file mode 100644 index 0000000..119894a --- /dev/null +++ b/lib/WWW/Pocket/Script.pm @@ -0,0 +1,130 @@ +package WWW::Pocket::Script; +use Moose; + +with 'MooseX::Getopt'; + +use JSON::PP; +use Path::Class; + +use WWW::Pocket; + +has consumer_key => ( + is => 'ro', + isa => 'Str', + lazy => 1, + default => sub { die "consumer_key is required to authenticate" }, +); + +has redirect_uri => ( + is => 'ro', + isa => 'Str', + default => 'https://getpocket.com/', +); + +has credentials_file => ( + is => 'ro', + isa => 'Str', + default => "$ENV{HOME}/.pocket", +); + +has pocket => ( + traits => ['NoGetopt'], + is => 'ro', + isa => 'WWW::Pocket', + lazy => 1, + default => sub { + my $self = shift; + + my $pocket = WWW::Pocket->new; + my $credentials_file = file($self->credentials_file); + if (-e $credentials_file) { + $self->_apply_credentials($pocket, $credentials_file); + } + else { + $self->_authenticate($pocket); + } + + $pocket + }, +); + +sub run { + my $self = shift; + my @args = @{ $self->extra_argv }; + + my $method = shift @args; + if ($self->can($method)) { + return $self->$method(@args); + } + else { + $self->print_usage_text($self->usage); + } +} + +sub authenticate { + my $self = shift; + $self->pocket; +} + +sub add { + my $self = shift; + my @args = @_; + + $self->_pretty_print($self->pocket->add(@args)); +} + +sub modify { + my $self = shift; + my @args = @_; + + $self->_pretty_print($self->pocket->modify(@args)); +} + +sub retrieve { + my $self = shift; + my @args = @_; + + $self->_pretty_print($self->pocket->retrieve(@args)); +} + +sub _apply_credentials { + my $self = shift; + my ($pocket, $file) = @_; + + my ($consumer_key, $access_token, $username) = $file->slurp(chomp => 1); + $pocket->consumer_key($consumer_key); + $pocket->access_token($access_token); + $pocket->username($username); +} + +sub _authenticate { + my $self = shift; + my ($pocket) = @_; + + my $consumer_key = $self->consumer_key; + my $redirect_uri = $self->redirect_uri; + my $code = $pocket->start_authentication($consumer_key, $redirect_uri); + + print "Visit https://getpocket.com/auth/authorize?request_token=${code}&redirect_uri=${redirect_uri} and log in. When you're done, press enter to continue.\n"; + ; + + $pocket->finish_authentication($consumer_key, $code); + + my $fh = file($self->credentials_file)->openw; + $fh->write($pocket->consumer_key . "\n"); + $fh->write($pocket->access_token . "\n"); + $fh->write($pocket->username . "\n"); + $fh->close; +} + +sub _pretty_print { + my $self = shift; + my ($data) = @_; + + print JSON::PP->new->utf8->pretty->canonical->encode($data), "\n"; +} + +__PACKAGE__->meta->make_immutable; +no Moose; + +1; -- cgit v1.2.3