CapnKernul/zeppelin

View on GitHub
lib/zeppelin.rb

Summary

Maintainability
B
4 hrs
Test Coverage
require 'faraday'
require 'faraday_middleware'
require 'time'

# A very tiny Urban Airship Push Notification API client.
#
# Provides thin wrappers around API calls to the most common API tasks. For more
# information on how the requests and responses are formatted, visit the [Urban
# Airship Push Notification API docs](http://urbanairship.com/docs/push.html).
class Zeppelin
  BASE_URI = 'https://go.urbanairship.com'
  PUSH_URI = '/api/push/'
  BATCH_PUSH_URI = '/api/push/batch/'
  BROADCAST_URI = '/api/push/broadcast/'
  JSON_HEADERS = { 'Content-Type' => 'application/json' }

  attr_reader :application_key, :application_master_secret, :options

  # @param [String] application_key your Urban Airship Application Key
  #
  # @param [String] application_master_secret your Urban Airship Application
  #   Master Secret
  def initialize(application_key, application_master_secret, options = {})
    @application_key = application_key
    @application_master_secret = application_master_secret
    @options = options
  end

  # The connection to UrbanAirship
  def connection
    return @connection if defined?(@connection)
    @connection = initialize_connection
  end

  # Registers an iPhone device token.
  #
  # @param [String] device_token
  # @param [Hash] payload the payload to send during registration
  #
  # @return [Boolean] whether or not the registration was successful
  #
  # @raise [Zeppelin::ClientError] malformed request
  def register_device_token(device_token, payload = {})
    uri = device_token_uri(device_token)
    put_request(uri, payload)
  end

  # Registers an Android APID.
  #
  # @param [String] apid
  #
  # @param [Hash] payload the payload to send during registration
  #
  # @return [Boolean] whether or not the registration was successful
  #
  # @raise [Zeppelin::ClientError] invalid payload format
  def register_apid(apid, payload = {})
    uri = apid_uri(apid)
    put_request(uri, payload)
  end

  # Registers a Blackberry PIN
  #
  # @param [String] pin
  #
  # @param [Hash] payload the payload to send during registration
  #
  # @return [Boolean] whether or not the registration was successful
  #
  # @raise [Zeppelin::ClientError] invalid payload format
  #
  # @see http://urbanairship.com/docs/blackberry.html#registration
  def register_pin(pin, payload = {})
    uri = pin_uri(pin)
    put_request(uri, payload)
  end

  # Retrieves information on a device token.
  #
  # @param [String] device_token
  # @return [Hash, nil]
  #
  # @raise [Zeppelin::ResourceNotFound] invalid device token provided
  def device_token(device_token)
    uri = device_token_uri(device_token)
    get_request(uri)
  end

  # Retrieves information on an APID.
  #
  # @param [String] apid
  #
  # @return [Hash, nil]
  #
  # @raise [Zeppelin::ResourceNotFound] invalid APID provided
  def apid(apid)
    uri = apid_uri(apid)
    get_request(uri)
  end

  # @param [String] pin
  #
  # @return [Hash, nil]
  #
  # @raise [Zeppelin::ResourceNotFound] invalid PIN provided
  def pin(pin)
    uri = pin_uri(pin)
    get_request(uri)
  end

  # Deletes a device token.
  #
  # @param [String] device_token
  #
  # @return [Boolean] whether or not the deletion was successful
  #
  # @raise [Zeppelin::ResourceNotFound] invalid device token provided
  def delete_device_token(device_token)
    uri = device_token_uri(device_token)
    delete_request(uri)
  end

  # Deletes an APID.
  #
  # @param [String] apid
  #
  # @return [Boolean] whether or not the deletion was successful
  #
  # @raise [Zeppelin::ResourceNotFound] invalid APID provided
  def delete_apid(apid)
    uri = apid_uri(apid)
    delete_request(uri)
  end

  # Deletes a PIN
  #
  # @param [String] pin
  #
  # @return [Boolean] whether or not deletion was successful
  #
  # @raise [Zeppelin::ResourceNotFound] invalid PIN provided
  def delete_pin(pin)
    uri = pin_uri(pin)
    delete_request(uri)
  end

  # Retrieve a page of device tokens
  #
  # @param [Integer] page (nil) Page of device tokens to retrieve
  #
  # @return [Hash] result set. See documentation for details
  #
  # @Note that the next page number is included in the result set instead of the
  #   raw URI to request for the next page
  #
  # @raise [Zeppelin::ClientError] invalid request
  def device_tokens(page=nil)
    uri = device_token_uri(nil, :page => page)
    get_paged_request(uri)
  end

  # Retrieve a page of APIDs
  #
  # @param [Integer] page (nil) Page of APIDs to retrieve
  #
  # @return [Hash] result set. See documentation for details
  #
  # @Note that the next page number is included in the result set instead of the
  #   raw URI to request for the next page
  #
  # @raise [Zeppelin::ClientError] invalid request
  def apids(page=nil)
    uri = apid_uri(nil, :page => page)
    get_paged_request(uri)
  end

  # Pushes a message.
  #
  # @param [Hash] payload the payload of the message
  #
  # @return [Boolean] whether or not pushing the message was successful
  #
  # @raise [Zeppelin::ClientError] invalid payload format
  def push(payload)
    post_request(PUSH_URI, payload)
  end

  # Batch pushes multiple messages.
  #
  # @param [<Hash>] payload the payloads of each message
  #
  # @return [Boolean] whether or not pushing the messages was successful
  #
  # @raise [Zeppelin::ClientError] invalid payload format
  def batch_push(*payload)
    post_request(BATCH_PUSH_URI, payload)
  end

  # Broadcasts a message.
  #
  # @param [Hash] payload the payload of the message
  #
  # @return [Boolean] whether or not broadcasting the message was successful
  #
  # @raise [Zeppelin::ClientError] invalid payload format
  def broadcast(payload)
    post_request(BROADCAST_URI, payload)
  end

  # Retrieves feedback on device tokens.
  #
  # This is useful for removing inactive device tokens for the database.
  #
  # @param [Time] since the time to retrieve inactive tokens from
  #
  # @return [Hash, nil]
  #
  # @raise [Zeppelin::ClientError] invalid time param
  def feedback(since)
    uri = feedback_uri(since)
    get_request(uri)
  end

  # Retrieve all tags on the service
  #
  # @return [Hash, nil]
  def tags
    uri = tag_uri(nil)
    get_request(uri)
  end

  # Modifies device tokens associated with a tag.
  #
  # @param [String] tag The name of the tag to modify tag associations on
  #
  # @param [Hash] payload
  #
  # @see http://urbanairship.com/docs/tags.html#modifying-device-tokens-on-a-tag
  def modify_device_tokens_on_tag(tag_name, payload = {})
    uri = tag_uri(tag_name)
    post_request(uri, payload)
  end

  # Creates a tag that is not associated with any device
  #
  # @param [#to_s] name The name of the tag to add
  #
  # @return [Boolean] whether or not the request was successful
  def add_tag(name)
    uri = tag_uri(name)
    put_request(uri)
  end

  # Removes a tag from the service
  #
  # @param [#to_s] name The name of the tag to remove
  #
  # @return [Boolean] true when the request was successful. Note that this
  #   method will return false if the tag has already been removed.
  #
  # @raise [Zeppelin::ResourceNotFound] tag already removed
  def remove_tag(name)
    uri = tag_uri(name)
    delete_request(uri)
  end

  # @param [String] device_token
  #
  # @return [Hash, nil]
  #
  # @raise [Zeppelin::ResourceNotFound] device does not exist
  def device_tags(device_token)
    uri = device_tag_uri(device_token, nil)
    get_request(uri)
  end

  # @param [String] device_token
  #
  # @param [#to_s] tag_name
  #
  # @return [Boolean] whether or not a tag was successfully associated with
  #   a device
  #
  # @raise [Zeppelin::ResourceNotFound] device does not exist
  def add_tag_to_device(device_token, tag_name)
    uri = device_tag_uri(device_token, tag_name)
    put_request(uri)
  end

  # @param [String] device_token
  #
  # @param [#to_s] tag_name
  #
  # @return [Boolean] whether or not a tag was successfully dissociated from
  #   a device
  #
  # @raise [Zeppelin::ResourceNotFound] device does not exist
  def remove_tag_from_device(device_token, tag_name)
    uri = device_tag_uri(device_token, tag_name)
    delete_request(uri)
  end

  private

  def initialize_connection
    conn = Faraday::Connection.new(BASE_URI, @options) do |builder|
      builder.request :json

      builder.response :json, :content_type => /\bjson$/
      builder.response :zeppelin_raise_error

      builder.adapter :net_http
    end

    conn.basic_auth(@application_key, @application_master_secret)

    conn
  end

  def put_request(uri, payload={})
    if !(payload.nil? || payload.empty?)
      response = connection.put(uri, payload, JSON_HEADERS)
    else
      response = connection.put(uri)
    end

    response.success?
  end

  def delete_request(uri)
    connection.delete(uri).success?
  end

  def get_request(uri)
    response = connection.get(uri)
    response.body if response.success?
  end

  def get_paged_request(uri)
    results = get_request(uri)
    md      = results['next_page'] && results['next_page'].match(/(start|page)=(\d+)/)

    results['next_page'] = md[2].to_i unless md.nil?

    results
  end

  def post_request(uri, payload)
    connection.post(uri, payload, JSON_HEADERS).success?
  end

  def query_string(query)
    '?' + query.map { |k, v| "#{k}=#{v}" }.join('&')
  end

  def device_token_uri(device_token, query={})
    uri  = "/api/device_tokens/#{device_token}"
    uri << query_string(query) unless query.empty?
    uri
  end

  def apid_uri(apid, query={})
    uri =  "/api/apids/#{apid}"
    uri << query_string(query) unless query.empty?
    uri
  end

  def feedback_uri(since)
    "/api/device_tokens/feedback/?since=#{since.utc.iso8601}"
  end

  def tag_uri(name)
    "/api/tags/#{name}"
  end

  def device_tag_uri(device_token, tag_name)
    device_token_uri(device_token) + "/tags/#{tag_name}"
  end

  def pin_uri(pin)
    "/api/device_pins/#{pin}/"
  end
end

require 'zeppelin/middleware'
require 'zeppelin/version'