Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
createsend-ruby/lib/createsend/createsend.rb
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
289 lines (258 sloc)
9.79 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'cgi' | |
require 'uri' | |
require 'httparty' | |
require 'hashie' | |
require 'json' | |
module CreateSend | |
USER_AGENT_STRING = "createsend-ruby-#{VERSION}-#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}-#{RUBY_PLATFORM}" | |
# Represents a CreateSend API error. Contains specific data about the error. | |
class CreateSendError < StandardError | |
attr_reader :data | |
def initialize(data) | |
@data = data | |
# @data should contain Code, Message and optionally ResultData | |
extra = @data.ResultData ? "\nExtra result data: #{@data.ResultData}" : "" | |
super "The CreateSend API responded with the following error"\ | |
" - #{@data.Code}: #{@data.Message}#{extra}" | |
end | |
end | |
# Raised for HTTP response codes of 400...500 | |
class ClientError < StandardError; end | |
# Raised for HTTP response codes of 500...600 | |
class ServerError < StandardError; end | |
# Raised for HTTP response code of 400 | |
class BadRequest < CreateSendError; end | |
# Raised for HTTP response code of 401 | |
class Unauthorized < CreateSendError; end | |
# Raised for HTTP response code of 404 | |
class NotFound < ClientError; end | |
# Raised for HTTP response code of 401, specifically when an OAuth token | |
# in invalid (Code: 120, Message: 'Invalid OAuth Token') | |
class InvalidOAuthToken < Unauthorized; end | |
# Raised for HTTP response code of 401, specifically when an OAuth token | |
# has expired (Code: 121, Message: 'Expired OAuth Token') | |
class ExpiredOAuthToken < Unauthorized; end | |
# Raised for HTTP response code of 401, specifically when an OAuth token | |
# has been revoked (Code: 122, Message: 'Revoked OAuth Token') | |
class RevokedOAuthToken < Unauthorized; end | |
# Provides high level CreateSend functionality/data you'll probably need. | |
class CreateSend | |
include HTTParty | |
attr_reader :auth_details | |
# Specify cert authority file for cert validation | |
ssl_ca_file File.expand_path(File.join(File.dirname(__FILE__), 'cacert.pem')) | |
# Set a custom user agent string to be used when instances of | |
# CreateSend::CreateSend make API calls. | |
# | |
# user_agent - The user agent string to use in the User-Agent header when | |
# instances of this class make API calls. If set to nil, the | |
# default value of CreateSend::USER_AGENT_STRING will be used. | |
def self.user_agent(user_agent) | |
headers({'User-Agent' => user_agent || USER_AGENT_STRING}) | |
end | |
# Get the authorization URL for your application, given the application's | |
# client_id, redirect_uri, scope, and optional state data. | |
def self.authorize_url(client_id, redirect_uri, scope, state=nil) | |
qs = "client_id=#{CGI.escape(client_id.to_s)}" | |
qs << "&redirect_uri=#{CGI.escape(redirect_uri.to_s)}" | |
qs << "&scope=#{CGI.escape(scope.to_s)}" | |
qs << "&state=#{CGI.escape(state.to_s)}" if state | |
"#{@@oauth_base_uri}?#{qs}" | |
end | |
# Exchange a provided OAuth code for an OAuth access token, 'expires in' | |
# value, and refresh token. | |
def self.exchange_token(client_id, client_secret, redirect_uri, code) | |
body = "grant_type=authorization_code" | |
body << "&client_id=#{CGI.escape(client_id.to_s)}" | |
body << "&client_secret=#{CGI.escape(client_secret.to_s)}" | |
body << "&redirect_uri=#{CGI.escape(redirect_uri.to_s)}" | |
body << "&code=#{CGI.escape(code.to_s)}" | |
options = {:body => body} | |
response = HTTParty.post(@@oauth_token_uri, options) | |
if response.has_key? 'error' and response.has_key? 'error_description' | |
err = "Error exchanging code for access token: " | |
err << "#{response['error']} - #{response['error_description']}" | |
raise err | |
end | |
r = Hashie::Mash.new(response) | |
[r.access_token, r.expires_in, r.refresh_token] | |
end | |
# Refresh an OAuth access token, given an OAuth refresh token. | |
# Returns a new access token, 'expires in' value, and refresh token. | |
def self.refresh_access_token(refresh_token) | |
options = { | |
:body => "grant_type=refresh_token&refresh_token=#{CGI.escape(refresh_token)}" } | |
response = HTTParty.post(@@oauth_token_uri, options) | |
if response.has_key? 'error' and response.has_key? 'error_description' | |
err = "Error refreshing access token: " | |
err << "#{response['error']} - #{response['error_description']}" | |
raise err | |
end | |
r = Hashie::Mash.new(response) | |
[r.access_token, r.expires_in, r.refresh_token] | |
end | |
def initialize(*args) | |
if args.size > 0 | |
auth args.first # Expect auth details as first argument | |
end | |
end | |
@@base_uri = "https://api.createsend.com/api/v3.1" | |
@@oauth_base_uri = "https://api.createsend.com/oauth" | |
@@oauth_token_uri = "#{@@oauth_base_uri}/token" | |
headers({ | |
'User-Agent' => USER_AGENT_STRING, | |
'Content-Type' => 'application/json; charset=utf-8', | |
'Accept-Encoding' => 'gzip, deflate' }) | |
base_uri @@base_uri | |
# Authenticate using either OAuth or an API key. | |
def auth(auth_details) | |
@auth_details = auth_details | |
end | |
# Refresh the current OAuth token using the current refresh token. | |
def refresh_token | |
if not @auth_details or | |
not @auth_details.has_key? :refresh_token or | |
not @auth_details[:refresh_token] | |
raise '@auth_details[:refresh_token] does not contain a refresh token.' | |
end | |
access_token, expires_in, refresh_token = | |
self.class.refresh_access_token @auth_details[:refresh_token] | |
auth({ | |
:access_token => access_token, | |
:refresh_token => refresh_token}) | |
[access_token, expires_in, refresh_token] | |
end | |
# Gets your clients. | |
def clients | |
response = get('/clients.json') | |
response.map{|item| Hashie::Mash.new(item)} | |
end | |
# Get your billing details. | |
def billing_details | |
response = get('/billingdetails.json') | |
Hashie::Mash.new(response) | |
end | |
# Gets valid countries. | |
def countries | |
response = get('/countries.json') | |
response.parsed_response | |
end | |
# Gets the current date in your account's timezone. | |
def systemdate | |
response = get('/systemdate.json') | |
Hashie::Mash.new(response) | |
end | |
# Gets valid timezones. | |
def timezones | |
response = get('/timezones.json') | |
response.parsed_response | |
end | |
# Gets the administrators for the account. | |
def administrators | |
response = get('/admins.json') | |
response.map{|item| Hashie::Mash.new(item)} | |
end | |
# Gets the primary contact for the account. | |
def get_primary_contact | |
response = get('/primarycontact.json') | |
Hashie::Mash.new(response) | |
end | |
# Set the primary contect for the account. | |
def set_primary_contact(email) | |
options = { :query => { :email => email } } | |
response = put("/primarycontact.json", options) | |
Hashie::Mash.new(response) | |
end | |
# Get a URL which initiates a new external session for the user with the | |
# given email. | |
# Full details: http://www.campaignmonitor.com/api/account/#single_sign_on | |
# | |
# email - The email address of the Campaign Monitor user for whom | |
# the login session should be created. | |
# chrome - Which 'chrome' to display - Must be either "all", | |
# "tabs", or "none". | |
# url - The URL to display once logged in. e.g. "/subscribers/" | |
# integrator_id - The integrator ID. You need to contact Campaign Monitor | |
# support to get an integrator ID. | |
# client_id - The Client ID of the client which should be active once | |
# logged in to the Campaign Monitor account. | |
# | |
# Returns An object containing a single field SessionUrl which represents | |
# the URL to initiate the external Campaign Monitor session. | |
def external_session_url(email, chrome, url, integrator_id, client_id) | |
options = { :body => { | |
:Email => email, | |
:Chrome => chrome, | |
:Url => url, | |
:IntegratorID => integrator_id, | |
:ClientID => client_id }.to_json } | |
response = put("/externalsession.json", options) | |
Hashie::Mash.new(response) | |
end | |
def get(*args) | |
args = add_auth_details_to_options(args) | |
handle_response CreateSend.get(*args) | |
end | |
alias_method :cs_get, :get | |
def post(*args) | |
args = add_auth_details_to_options(args) | |
handle_response CreateSend.post(*args) | |
end | |
alias_method :cs_post, :post | |
def put(*args) | |
args = add_auth_details_to_options(args) | |
handle_response CreateSend.put(*args) | |
end | |
alias_method :cs_put, :put | |
def delete(*args) | |
args = add_auth_details_to_options(args) | |
handle_response CreateSend.delete(*args) | |
end | |
alias_method :cs_delete, :delete | |
def add_auth_details_to_options(args) | |
if @auth_details | |
options = {} | |
if args.size > 1 | |
options = args[1] | |
end | |
if @auth_details.has_key? :access_token | |
options[:headers] = { | |
"Authorization" => "Bearer #{@auth_details[:access_token]}" } | |
elsif @auth_details.has_key? :api_key | |
if not options.has_key? :basic_auth | |
options[:basic_auth] = { | |
:username => @auth_details[:api_key], :password => 'x' } | |
end | |
end | |
args[1] = options | |
end | |
args | |
end | |
def handle_response(response) # :nodoc: | |
case response.code | |
when 400 | |
raise BadRequest.new(Hashie::Mash.new response) | |
when 401 | |
data = Hashie::Mash.new(response) | |
case data.Code | |
when 120 | |
raise InvalidOAuthToken.new data | |
when 121 | |
raise ExpiredOAuthToken.new data | |
when 122 | |
raise RevokedOAuthToken.new data | |
else | |
raise Unauthorized.new data | |
end | |
when 404 | |
raise NotFound.new | |
when 400...500 | |
raise ClientError.new | |
when 500...600 | |
raise ServerError.new | |
else | |
response | |
end | |
end | |
end | |
end |