Module: Instagram::Client::Subscriptions

Included in:
Instagram::Client
Defined in:
lib/instagram/client/subscriptions.rb

Overview

Defines methods related to real-time

Instance Method Summary collapse

Instance Method Details

#create_subscription(options = {}) ⇒ Object #create_subscription(object, callback_url, aspect = "media", options = {}) ⇒ Hashie::Mash

Creates a real-time subscription

Overloads:

  • #create_subscription(options = {}) ⇒ Object

    Options Hash (options):

    • :object (String)

      The object you'd like to subscribe to (user, tag, location or geography)

    • :callback_url (String)

      The subscription callback URL

    • :aspect (String)

      The aspect of the object you'd like to subscribe to (in this case, "media").

    • :object_id (String, Integer)

      When specifying a location or tag use the location's ID or tag name respectively

    • :lat (String, Float)

      The center latitude of an area, used when subscribing to a geography object

    • :lng (String, Float)

      The center longitude of an area, used when subscribing to a geography object

    • :radius (String, Integer)

      The distance in meters you'd like to capture around a given point

  • #create_subscription(object, callback_url, aspect = "media", options = {}) ⇒ Hashie::Mash

    Returns The subscription created.

    Examples:

    Creates a new subscription to receive notifications for user media changes.

    Instagram.create_subscription("user", "http://example.com/instagram/callback")
    

    Options Hash (options):

    • :object_id (String, Integer)

      When specifying a location or tag use the location's ID or tag name respectively

    • :lat (String, Float)

      The center latitude of an area, used when subscribing to a geography object

    • :lng (String, Float)

      The center longitude of an area, used when subscribing to a geography object

    • :radius (String, Integer)

      The distance in meters you'd like to capture around a given point

      Note that we only support "media" at this time, but we might support other types of subscriptions in the future.

See Also:

Supported formats:

  • :json

Requires Authentication:

  • true

    Requires client_secret to be set on the client or passed in options

Rate Limited:

  • true



56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/instagram/client/subscriptions.rb', line 56

def create_subscription(*args)
  options = args.last.is_a?(Hash) ? args.pop : {}
  object = args.shift
  callback_url = args.shift
  aspect = args.shift
  options.tap {|o|
    o[:object] = object unless object.nil?
    o[:callback_url] = callback_url unless callback_url.nil?
    o[:aspect] = aspect || o[:aspect] || "media"
  }
  response = post("subscriptions", options.merge(:client_secret => client_secret), signature=true)
  response
end

#delete_subscription(options = {}) ⇒ Object #delete_subscription(subscription_id, options = {}) ⇒ Hashie::Mash

Deletes a real-time subscription

Overloads:

  • #delete_subscription(options = {}) ⇒ Object

    Options Hash (options):

    • :subscription_id (Integer)

      The subscription's ID

    • :object (String)

      When specified will remove all subscriptions of this object type, unless an :object_id is also specified (user, tag, location or geography)

    • :object_id (String, Integer)

      When specifying :object, inlcude an :object_id to only remove subscriptions of that object and object_id

  • #delete_subscription(subscription_id, options = {}) ⇒ Hashie::Mash

    Examples:

    Deletes an application's user change subscription

    Instagram.delete_subscription(:object => "user")
    

    Options Hash (options):

    • :object (String)

      When specified will remove all subscriptions of this object type, unless an :object_id is also specified (user, tag, location or geography)

    • :object_id (String, Integer)

      When specifying :object, inlcude an :object_id to only remove subscriptions of that object and object_id

See Also:

Supported formats:

  • :json

Requires Authentication:

  • true

    Requires client_secret to be set on the client or passed in options

Rate Limited:

  • true



91
92
93
94
95
96
97
# File 'lib/instagram/client/subscriptions.rb', line 91

def delete_subscription(*args)
  options = args.last.is_a?(Hash) ? args.pop : {}
  subscription_id = args.first
  options.merge!(:id => subscription_id) if subscription_id
  response = delete("subscriptions", options.merge(:client_secret => client_secret), signature=true)
  response
end

#meet_challenge(params, verify_token = nil) { ... } ⇒ Object

As a security measure (to prevent DDoS attacks), Instagram sends a verification request to your server after you request a subscription. This method parses the challenge params and makes sure the call is legitimate.

Yields:

  • verify_token if you need to compute the verification token (for instance, if your callback URL includes a record ID, which you look up and use to calculate a hash), you can pass meet_challenge a block, which will receive the verify_token received back from Instagram.



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/instagram/client/subscriptions.rb', line 112

def meet_challenge(params, verify_token = nil, &verification_block)
  if params["hub.mode"] == "subscribe" &&
      # you can make sure this is legitimate through two ways
      # if your store the token across the calls, you can pass in the token value
      # and we'll make sure it matches
      ((verify_token && params["hub.verify_token"] == verify_token) ||
      # alternately, if you sent a specially-constructed value (such as a hash of various secret values)
      # you can pass in a block, which we'll call with the verify_token sent by Instagram
      # if it's legit, return anything that evaluates to true; otherwise, return nil or false
      (verification_block && yield(params["hub.verify_token"])))
    params["hub.challenge"]
  else
    false
  end
end

#process_subscription(json, &block) ⇒ nil

Process a subscription notification JSON payload

Examples:

Process and handle a notification for a user media change

Instagram.process_subscription(params[:body]) do |handler|

  handler.on_user_changed do |user_id, data|

    user = User.by_instagram_id(user_id)
    @client = Instagram.client(:access_token => _access_token_for_user(user))
    latest_media = @client.user_recent_media[0]
    user.media.create_with_hash(latest_media)
  end

end

Raises:

  • (ArgumentError)

See Also:

Supported formats:

  • :json

Requires Authentication:

  • true

    Requires client_secret to be set on the client or passed in options

Rate Limited:

  • true



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/instagram/client/subscriptions.rb', line 177

def process_subscription(json, options={}, &block)
  raise ArgumentError, "callbacks block expected" unless block_given?

  if options.has_key?(:signature)
    if !client_secret
      raise ArgumentError, "client_secret must be set during configure"
    end
    digest = OpenSSL::Digest.new('sha1')
    verify_signature = OpenSSL::HMAC.hexdigest(digest, client_secret, json)

    if options[:signature] != verify_signature
      raise Instagram::InvalidSignature, "invalid X-Hub-Signature does not match verify signature against client_secret"
    end
  end

  payload = MultiJson.decode(json)
  @changes = Hash.new { |h,k| h[k] = [] }
  for change in payload
    @changes[change['object']] << change
  end
  block.call(self)
end

#subscriptions(options = {}) ⇒ Hashie::Mash

Returns a list of active real-time subscriptions

Returns The list of subscriptions.

Examples:

Returns a list of subscriptions for the authenticated application

Instagram.subscriptions

See Also:

Supported formats:

  • :json

Requires Authentication:

  • true

    Requires client_secret to be set on the client or passed in options

Rate Limited:

  • true



20
21
22
23
# File 'lib/instagram/client/subscriptions.rb', line 20

def subscriptions(options={})
  response = get("subscriptions", options.merge(:client_secret => client_secret))
  response
end

#validate_update(body, headers) ⇒ Object

Public: As a security measure, all updates from Instagram are signed using X-Hub-Signature: XXXX where XXX is the sha1 of the json payload using your application secret as the key.

Example: # in Rails controller def receive_update if Instagram.validate_update(request.body, headers) ... else render text: "not authorized", status: 401 end end



141
142
143
144
145
146
147
148
149
150
# File 'lib/instagram/client/subscriptions.rb', line 141

def validate_update(body, headers)
  unless client_secret
    raise ArgumentError, "client_secret must be set during configure"
  end

  if request_signature = headers['X-Hub-Signature'] || headers['HTTP_X_HUB_SIGNATURE']
    calculated_signature = OpenSSL::HMAC.hexdigest('sha1', client_secret, body)
    calculated_signature == request_signature
  end
end