Permalink
Browse files

Completed version 1 of the API and pushed to CPAN

  • Loading branch information...
1 parent 837bfa6 commit 1100223c157a73141f32a9af878dc19dce56fc75 Jonathan Lloyd committed Jan 12, 2012
Showing with 424 additions and 29 deletions.
  1. +30 −0 dist.ini
  2. +96 −6 lib/WebService/SendGrid.pm
  3. +34 −23 lib/WebService/SendGrid/Mail.pm
  4. +138 −0 lib/WebService/SendGrid/Profile.pm
  5. +27 −0 t/03_profile.t
  6. +99 −0 t/04_mail.t
View
@@ -0,0 +1,30 @@
+name = WebService-SendGrid
+author = Jonathan Lloyd <webmaster@lifegames.org>
+license = Perl_5
+copyright_holder = Jonathan Lloyd <webmaster@lifegames.org>
+copyright_year = 2011
+version = 1.0
+
+[@Basic]
+[PkgVersion]
+[PodWeaver]
+[Prereqs]
+Moose = 2
+Moose::Util::TypeConstraints = 2
+MooseX::Method::Signatures = 0.36
+
+URI = 0
+Carp = 0
+JSON::XS = 2.3
+DateTime::Format::Mail = 0
+HTTP::Request = 0
+HTTP::Response = 0
+
+[Prereqs / TestRequires]
+Test::More = 0.96
+Try::Tiny = 0.09
+Data::Dumper = 0
+
+[TestRelease]
+[ConfirmRelease]
+[UploadToCPAN]
View
@@ -1,21 +1,111 @@
package WebService::SendGrid;
+# ABSTRACT: An interface to the SendGrid email service
use Moose;
use MooseX::Method::Signatures;
-with 'WebService::Dispatcher::Curl';
+use Carp;
+use JSON::XS;
+use WWW::Curl::Simple;
+use HTTP::Request;
+
+has 'user_agent' => (
+ is => 'ro',
+ isa => 'WWW::Curl::Simple',
+ required => 1,
+ default => sub {
+ return WWW::Curl::Simple->new();
+ }
+);
+
+has 'test_mode' => (
+ is => 'rw',
+ isa => 'Bool',
+ default => 0,
+);
has 'api_user' => (
is => 'rw',
isa => 'Str',
- required => 1,
- default => 'webmaster@lifegames.org'
+ required => 1
);
+
has 'api_key' => (
is => 'rw',
isa => 'Str',
- required => 1,
- default => 'b5l2v2v3970f16gJRL80'
+ required => 1
);
-has 'api_uri' => (is => 'ro', isa => 'Str', default => 'https://sendgrid.com/api/mail.send.json');
+
+method _generate_request (Str $path, HashRef $data) {
+
+ # add the api_user and api_key to the query string
+ $data->{$_} = $self->$_ for qw(api_user api_key);
+
+ my $uri = URI->new('https:');
+ $uri->query_form(%$data);
+
+ my $req = HTTP::Request->new;
+ $req->method('POST');
+ $req->uri('https://sendgrid.com' . $path);
+ $req->content($uri->query);
+ return $req;
+
+}
+
+method _process_error (Object $res) {
+ croak 'Response is not an HTTP::Response object' if ref $res ne 'HTTP::Response';
+
+ print Data::Dumper::Dumper($res);
+
+}
+
+method _dispatch_test_request (Object $req) {
+
+ my $content;
+ if ($req->uri->path eq '/api/profile.get.json') {
+ my %profile = (
+ username => 'jlloyd',
+ email => 'jlloyd@cpan.org',
+ website_access => 'true',
+ active => 'true',
+ );
+ $content = encode_json( [ \%profile ]);
+ }
+ else {
+ $content = encode_json( { message => 'success' });
+ }
+
+ my $res = HTTP::Response->new;
+ $res->code(200);
+ $res->content( $content );
+ return $res;
+}
+
+method _dispatch_request (Object $req) {
+ croak 'Request is not an HTTP::Request object' if ref $req ne 'HTTP::Request';
+
+ # if the module is being called from a test file
+ # always send a successful response
+ return $self->_dispatch_test_request($req) if $self->test_mode == 1;
+
+
+ #$self->log->info('Sending request');
+ my $res = $self->user_agent->request($req);
+ return $res;
+
+}
+
+=head1 DESCRIPTION
+
+This module is the parent class for an interface to the SendGrid Web API. To use it, refer to the individual classes below.
+
+=head1 SEE ALSO
+
+=for :list
+* L<WebService::SendGrid::Mail>
+* L<WebService::SendGrid::Profile>
+
+=cut
1;
+
+
@@ -1,16 +1,21 @@
package WebService::SendGrid::Mail;
+# ABSTRACT: An email class for sending a message through SendGrid
use Moose;
+use Moose::Util::TypeConstraints;
use MooseX::Method::Signatures;
+use namespace::autoclean;
-extends 'SendGrid';
+extends 'WebService::SendGrid';
use URI;
use Carp;
use JSON::XS;
use Data::Show;
-use Util::Types qw(Email);
use DateTime::Format::Mail;
+use Mail::RFC822::Address qw(valid);
+subtype 'Email', as 'Str', where { valid($_) };
+
has 'to' => ( is => 'rw', isa => 'Email | ArrayRef[Email]', required => 1 );
has 'toname' => ( is => 'rw', isa => 'Str | ArrayRef', required => 0 );
has 'bcc' => ( is => 'rw', isa => 'Email | ArrayRef[Email]', required => 0 );
@@ -20,6 +25,7 @@ has 'replyto' => ( is => 'rw', isa => 'Email', required => 0 );
has 'x-smtpapi' => ( is => 'rw', isa => 'Str', required => 0 );
has 'subject' => ( is => 'rw', isa => 'Str', required => 1 );
has 'files' => ( is => 'rw', isa => 'HashRef', required => 0 );
+# Must be less than 7MB
# files[file1.doc]=example.doc&files[file2.pdf]=example.pdf
has 'headers' => ( is => 'rw', isa => 'HashRef', required => 0 );
# A collection of key/value pairs in JSON format
@@ -30,10 +36,9 @@ has 'date' => ( is => 'rw', isa => 'Str', required => 1, default => sub {
has 'text' => ( is => 'rw', isa => 'Str', required => 0 );
has 'html' => ( is => 'rw', isa => 'Str', required => 0 );
-
method send {
- # must have text and/or HTML
- croak "No content" unless ( $self->text || $self->html );
+ # must have text and/or HTML
+ croak "No content" unless ( $self->text || $self->html );
my %data;
for my $attr ( $self->meta->get_all_attributes ) {
@@ -42,26 +47,32 @@ method send {
$data{$name} = $self->$name if $self->$name;
}
- $data{$_} = $self->$_ for qw(api_user api_key);
-
- my $uri = URI->new('http:');
- $uri->query_form(%data);
-
- my $req = HTTP::Request->new;
- $req->method('POST');
- $req->uri($self->api_uri);
- $req->content($uri->query);
-
- # if the module is being called from a test file
- # always send a successful response
- my ($package, $filename, $line) = caller;
- return { message => 'success' } if $filename =~ /\.t$/;
-
- my $res = $self->http_request($req);
+ my $req = $self->_generate_request('/api/mail.send.json', \%data);
+ my $res = $self->_dispatch_request($req);
+ return $self->_process_error($res) if $res->code != 200;
my $content = decode_json $res->content;
- return $res->code == 200 ? $content : undef;
-
}
1;
+
+=head1 SYNOPSIS
+
+ use WebService::SendGrid::Mail;
+ my $mail = WebService::SendGrid::Mail->new(
+ api_user => 'jlloyd', # same username for logging into the website
+ api_key => 'abcdefgh123456789', # same password for logging into the website
+ to => 'jlloyd@cpan.org',
+ from => 'jlloyd@cpan.org',
+ subject => 'This is a test',
+ text => 'This is a test message',
+ html => '<html><head></head><body>This is a test HTML message</body></html>'
+ );
+
+ $mail->send;
+
+1;
+
+=head1 DESCRIPTION
+
+Allows you to send an email through the SendGrid Web API
@@ -0,0 +1,138 @@
+package WebService::SendGrid::Profile;
+# ABSTRACT: The Profile class for your SendGrid account
+use Moose;
+use Moose::Util::TypeConstraints;
+use MooseX::Method::Signatures;
+use namespace::autoclean;
+
+extends 'WebService::SendGrid';
+
+use URI;
+use Carp;
+use JSON::XS;
+use Mail::RFC822::Address qw(valid);
+
+has 'first_name' => ( is => 'rw', isa => 'Str', required => 0, documentation => 'Your first name' );
+has 'last_name' => ( is => 'rw', isa => 'Str', required => 0, documentation => 'Your last name' );
+has 'address' => ( is => 'rw', isa => 'Str', required => 0, documentation => 'Company address 1' );
+has 'address2' => ( is => 'rw', isa => 'Str', required => 0, documentation => 'Company address 2' );
+has 'city' => ( is => 'rw', isa => 'Str', required => 0, documentation => 'City where your company is located' );
+has 'state' => ( is => 'rw', isa => 'Str', required => 0, documentation => 'State where your company is located' );
+has 'country' => ( is => 'rw', isa => 'Str', required => 0, documentation => 'Country where your company is located' );
+has 'zip' => ( is => 'rw', isa => 'Str', required => 0, documentation => 'Zipcode where your company is located' );
+has 'phone' => ( is => 'rw', isa => 'Str', required => 0, documentation => 'Valid phone number where we can reach you' );
+has 'website' => ( is => 'rw', isa => 'Str', required => 0, documentation => 'Your company\'s website' );
+
+has 'username' => ( is => 'ro', isa => 'Str', required => 0, writer => '_set_username' );
+has 'email' => ( is => 'ro', isa => 'Str', required => 0, writer => '_set_email' );
+
+method BUILD {
+
+ my $req = $self->_generate_request('/api/profile.get.json', {});
+ my $res = $self->_dispatch_request($req);
+ return $self->_process_error($res) if $res->code != 200;
+ my $content = ${ decode_json $res->content }[0];
+
+ # iterate through the values of the class, and assign them if defined
+ for my $attr ( $self->meta->get_all_attributes ) {
+ next unless __PACKAGE__ eq $attr->definition_context->{package};
+ my $name = $attr->name;
+ my $method = $attr->get_write_method;
+ $self->$method($content->{$name}) if defined $content->{$name};
+ }
+
+ # there are two undocumented attributes that come back in this content
+ # - website_access (true|false)
+ # - active (true|false)
+ # - username
+ # - email
+ warn 'This user is inactive' if $content->{active} ne 'true';
+
+}
+
+method set {
+
+ my %data;
+ for my $attr ( $self->meta->get_all_attributes ) {
+ next unless __PACKAGE__ eq $attr->definition_context->{package};
+ my $name = $attr->name;
+ $data{$name} = $self->$name if $self->$name;
+ }
+
+ my $req = $self->_generate_request('/api/profile.set.json', \%data);
+ my $res = $self->_dispatch_request($req);
+ return $self->_process_error($res) if $res->code != 200;
+ my $content = decode_json $res->content;
+
+}
+
+method setUsername (Str $username) {
+ # Must not exceed 100 characters. The username cannot be already taken or contain the SendGrid.com domain
+ croak 'Username too long' if length $username > 100;
+
+ my $req = $self->_generate_request('/api/profile.setUsername.json', { username => $username });
+ my $res = $self->_dispatch_request($req);
+ return $self->_process_error($res) if $res->code != 200;
+ my $content = decode_json $res->content;
+
+}
+
+method setPassword (Str $password) {
+ # Must be at least 6 characters
+ croak 'Password too short' if length $password < 6;
+
+ my %data = (
+ password => $password,
+ confirm_password => $password
+ );
+
+ my $req = $self->_generate_request('/api/profile.setPassword.json', \%data);
+ my $res = $self->_dispatch_request($req);
+ return $self->_process_error($res) if $res->code != 200;
+ my $content = decode_json $res->content;
+
+}
+
+method setEmail (Str $email) {
+ # Must be in email format and not more than 100 characters
+ croak 'Email too long' if length $email > 100;
+ croak 'Invalid email' if !valid($email);
+
+ my $req = $self->_generate_request('/api/profile.setEmail.json', { email => $email });
+ my $res = $self->_dispatch_request($req);
+ return $self->_process_error($res) if $res->code != 200;
+ my $content = decode_json $res->content;
+
+}
+
+1;
+
+=head1 SYNOPSIS
+
+ use WebService::SendGrid::Profile;
+ my $profile = WebService::SendGrid::Profile->new(
+ api_user => 'jlloyd', # same username for logging into the website
+ api_key => 'abcdefgh123456789', # same password for logging into the website
+ );
+
+ print 'The username for your account is ' . $profile->username;
+ print 'The email for your account is ' . $profile->email;
+
+ $profile->address('123 Fake Street');
+ $profile->city('Faketown');
+ $profile->set; # store the new profile to SendGrid
+
+ # update the username on your account
+ $profile->setUsername('jlloyd');
+
+ # update the password on your account
+ $profile->setPassword('123456789');
+
+ # update the email address on your account
+ $profile->setEmail('jlloyd@cpan.org');
+
+1;
+
+=head1 DESCRIPTION
+
+Allows you to view/update your SendGrid profile using their Web API
Oops, something went wrong.

0 comments on commit 1100223

Please sign in to comment.