Group
Extension

WWW-PunchTab/lib/WWW/PunchTab.pm

package WWW::PunchTab;
{
    $WWW::PunchTab::VERSION = '0.02';
}

# ABSTRACT: PunchTab REST API

use strict;
use warnings;
use LWP::UserAgent;
use MIME::Base64;
use JSON;
use Digest::SHA;
use Carp;
use vars qw/$errstr/;
sub errstr { $errstr }

sub new {
    my $class = shift;
    my %args = @_ % 2 ? %{ $_[0] } : @_;

    $args{client_id}  or croak "client_id is required";
    $args{access_key} or croak "access_key is required";
    $args{secret_key} or croak "secret_key is required";
    $args{domain}     or croak "domain is required";
    $args{domain} = 'http://' . $args{domain}
      unless $args{domain} =~ '^https?\://';

    $args{ua} = LWP::UserAgent->new;

    bless \%args, $class;
}

sub sso_auth {
    my $self = shift;
    my %user = @_ % 2 ? %{ $_[0] } : @_;

    my $auth_request = encode_base64( encode_json( \%user ) );
    my $timestamp    = time();
    my $signature    = Digest::SHA::hmac_sha1_hex( "$auth_request $timestamp",
        $self->{secret_key} );

    my $resp = $self->{ua}->post(
        'https://api.punchtab.com/v1/auth/sso',
        'Referer' => $self->{domain},
        'Content' => [
            client_id    => $self->{client_id},
            key          => $self->{access_key},
            auth_request => $auth_request,
            timestamp    => $timestamp,
            signature    => $signature,
        ]
    );
    unless ( $resp->is_success ) {
        $errstr = $resp->status_line;
        return;
    }
    my $data = decode_json( $resp->decoded_content );
    if ( $data->{error} ) {
        $errstr = $data->{error}->{description};
        return;
    }
    $self->{__access_token} = $data->{authResponse}->{accessToken};
    return $data->{authResponse}->{accessToken};
}

sub sso_auth_js {
    my $self = shift;
    my %user = @_ % 2 ? %{ $_[0] } : @_;

    my $auth_request = encode_base64( encode_json( \%user ) );
    $auth_request =~ s/\n//g;
    my $timestamp = time();
    my $signature = Digest::SHA::hmac_sha1_hex( "$auth_request $timestamp",
        $self->{secret_key} );

    return <<JS;
var _pt_pre_config = {
    auth_request: '$auth_request',
    signature: '$signature',
    timestamp: $timestamp,
    client_id: $self->{client_id}
};
JS
}

sub auth_logout {
    my ($self) = @_;

    my $access_token = $self->{__access_token};
    my $resp         = $self->{ua}->post(
        "https://api.punchtab.com/v1/auth/logout",
        'Referer' => $self->{domain},
        'Content' => [
            access_token => $access_token,
            key          => $self->{access_key},
        ]
    );
    my $tmp = __deal_resp($resp);
    return unless $tmp;
    return $tmp->{status};
}

sub auth_status {
    my ( $self, $access_token ) = @_;

    $access_token ||= $self->{__access_token};
    my $resp = $self->{ua}->post(
        "https://api.punchtab.com/v1/auth/status",
        'Referer' => $self->{domain},
        'Content' => [
            access_token => $access_token,
            key          => $self->{access_key},
        ]
    );
    my $tmp = __deal_resp($resp);
    return unless $tmp;
    return $tmp->{status};
}

sub activity {
    my ( $self, $activity_name ) = @_;

    my $url = "https://api.punchtab.com/v1/activity";
    $url .= "/$activity_name" if $activity_name;
    $url .= "?access_token=" . $self->{__access_token};
    my $resp = $self->{ua}->get($url);
    return __deal_resp($resp);
}

sub create_activity {
    my ( $self, $action, $points ) = @_;

# visit, tweet, like, plusone, comment, invite, reply, apply, share, purchase, addtotimeline, search, download, view, checkin, subscribe, and follow
    my $access_token = $self->{__access_token};
    my $resp         = $self->{ua}->post(
"https://api.punchtab.com/v1/activity/$action?access_token=$access_token",
        [ $points ? ( 'points' => $points ) : () ]
    );
    return __deal_resp($resp);
}

sub redeem_reward {
    my ( $self, $reward_id ) = @_;
    my $access_token = $self->{__access_token};
    my $resp         = $self->{ua}->post(
"https://api.punchtab.com/v1/activity/redeem?access_token=$access_token",
        [ reward_id => $reward_id, ]
    );
    return __deal_resp($resp);
}

sub leaderboard {
    my $self         = shift;
    my %args         = @_ % 2 ? %{ $_[0] } : (@_);
    my $access_token = $self->{__access_token};
    my $resp         = $self->{ua}->get(
        "https://api.punchtab.com/v1/leaderboard",
        [
            access_token => $access_token,
            %args,
        ]
    );
    return __deal_resp($resp);
}

sub reward {
    my ( $self, $limit ) = @_;

    my $access_token = $self->{__access_token};
    my $url = "http://api.punchtab.com/v1/reward?access_token=" . $access_token;
    $url .= "&limit=$limit" if $limit;
    my $resp = $self->{ua}->get($url);
    return __deal_resp($resp);
}

sub user {
    my ($self) = @_;

    my $access_token = $self->{__access_token};
    my $resp =
      $self->{ua}
      ->get("https://api.punchtab.com/v1/user?access_token=$access_token");
    return __deal_resp($resp);
}

sub __deal_resp {
    my ($resp) = @_;
    unless ( $resp->is_success ) {
        $errstr = $resp->status_line;
        return;
    }
    my $data = decode_json( $resp->decoded_content );
    if ( ref $data eq 'HASH' and $data->{error} ) {
        $errstr = $data->{error}->{description};
        return;
    }
    return $data;
}

1;

__END__

=pod

=head1 NAME

WWW::PunchTab - PunchTab REST API

=head1 VERSION

version 0.02

=head1 SYNOPSIS

    use WWW::PunchTab;
    use Data::Dumper;

    my $pt = WWW::PunchTab->new(
        domain     => 'fayland.org',
        access_key => 'f4f8290698320a98b1044615e722af79',
        client_id  => '1104891876',
        secret_key => 'ed73f70966dd10b7788b8f7953ec1d07',
    );

    $pt->sso_auth(
        {'id' => '2', 'first_name' => 'Fayland', 'last_name' => 'Lam', 'email' => 'fayland@gmail.com'}
    ) or die $pt->errstr;

    my $x = $pt->create_activity('view', 200) or die $pt->errstr; # view with 200 points
    print Dumper(\$x);

=head1 DESCRIPTION

L<http://www.punchtab.com/developer-docs#REST-API-Documentation>

=head2 METHODS

=head3 CONSTRUCTION

    my $pt = WWW::PunchTab->new(
        domain     => 'fayland.org',
        access_key => 'f4f8290698320a98b1044615e722af79',
        client_id  => '1104891876',
        secret_key => 'ed73f70966dd10b7788b8f7953ec1d07',
    );

=over 4

=item * domain

=item * access_key

=item * client_id

=item * secret_key

All required.

=back

=head3 sso_auth

    $pt->sso_auth(
        {'id' => '2', 'first_name' => 'Fayland', 'last_name' => 'Lam', 'email' => 'fayland@gmail.com'}
    ) or die $pt->errstr;

=head3 sso_auth_js

    print $pt->sso_auth_js({'id' => '2', 'first_name' => 'Fayland', 'last_name' => 'Lam', 'email' => 'fayland@gmail.com'});

js sso auth example:

    var _pt_pre_config = {
        auth_request: 'xxx',
        signature: 'xxx',
        timestamp: 1348843966,
        client_id: 123
    };

=head3 auth_logout

    my $status = $pt->auth_logout or die $pt->errstr;

=head3 auth_status

return 'connected' or 'disconnected'

    my $status = $pt->auth_status($access_token) or die $pt->errstr;

=head3 activity

    my $activity = $pt->activity() or die $pt->errstr;
    my $activity = $pt->activity('like') or die $pt->errstr;

=head3 create_activity

     my $x = $pt->create_activity('view', 200) or die $pt->errstr; # view with 200 points

=head3 redeem_reward

     my $x = $pt->redeem_reward($reward_id) or die $pt->errstr;

=head3 leaderboard

     my $leaderboard = $pt->leaderboard() or die $pt->errstr;
     my $leaderboard = $pt->leaderboard(
        with => 'me',
        limit => 20,
        page  => 1,
     ) or die $pt->errstr;

=head3 reward

     my $reward = $pt->reward() or die $pt->errstr;
     my $reward = $pt->reward($limit) or die $pt->errstr;

=head3 user

     my $user = $pt->user() or die $pt->errstr;

=head1 AUTHOR

Fayland Lam <fayland@gmail.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2012 by Fayland Lam.

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

=cut


Powered by Groonga
Maintained by Kenichi Ishigaki <ishigaki@cpan.org>. If you find anything, submit it on GitHub.