instagram-continued 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/.yardopts +9 -0
- data/Gemfile +3 -0
- data/LICENSE.md +30 -0
- data/PATENTS.md +23 -0
- data/README.md +11 -0
- data/Rakefile +27 -0
- data/instagram.gemspec +30 -0
- data/lib/faraday/loud_logger.rb +75 -0
- data/lib/faraday/oauth2.rb +42 -0
- data/lib/faraday/raise_http_exception.rb +61 -0
- data/lib/instagram.rb +27 -0
- data/lib/instagram/api.rb +31 -0
- data/lib/instagram/client.rb +21 -0
- data/lib/instagram/client/comments.rb +62 -0
- data/lib/instagram/client/embedding.rb +28 -0
- data/lib/instagram/client/geographies.rb +29 -0
- data/lib/instagram/client/likes.rb +58 -0
- data/lib/instagram/client/locations.rb +75 -0
- data/lib/instagram/client/media.rb +82 -0
- data/lib/instagram/client/subscriptions.rb +211 -0
- data/lib/instagram/client/tags.rb +59 -0
- data/lib/instagram/client/users.rb +310 -0
- data/lib/instagram/client/utils.rb +28 -0
- data/lib/instagram/configuration.rb +122 -0
- data/lib/instagram/connection.rb +31 -0
- data/lib/instagram/error.rb +34 -0
- data/lib/instagram/oauth.rb +36 -0
- data/lib/instagram/request.rb +82 -0
- data/lib/instagram/response.rb +22 -0
- data/lib/instagram/version.rb +3 -0
- data/spec/faraday/response_spec.rb +87 -0
- data/spec/fixtures/access_token.json +9 -0
- data/spec/fixtures/approve_user.json +8 -0
- data/spec/fixtures/block_user.json +8 -0
- data/spec/fixtures/deny_user.json +8 -0
- data/spec/fixtures/follow_user.json +8 -0
- data/spec/fixtures/followed_by.json +1 -0
- data/spec/fixtures/follows.json +1 -0
- data/spec/fixtures/geography_recent_media.json +1 -0
- data/spec/fixtures/liked_media.json +1 -0
- data/spec/fixtures/location.json +1 -0
- data/spec/fixtures/location_recent_media.json +1 -0
- data/spec/fixtures/location_search.json +1 -0
- data/spec/fixtures/location_search_facebook.json +1 -0
- data/spec/fixtures/media.json +1 -0
- data/spec/fixtures/media_comment.json +1 -0
- data/spec/fixtures/media_comment_deleted.json +1 -0
- data/spec/fixtures/media_comments.json +1 -0
- data/spec/fixtures/media_liked.json +1 -0
- data/spec/fixtures/media_likes.json +1 -0
- data/spec/fixtures/media_popular.json +1 -0
- data/spec/fixtures/media_search.json +1 -0
- data/spec/fixtures/media_shortcode.json +1 -0
- data/spec/fixtures/media_unliked.json +1 -0
- data/spec/fixtures/mikeyk.json +1 -0
- data/spec/fixtures/oembed.json +14 -0
- data/spec/fixtures/recent_media.json +1 -0
- data/spec/fixtures/relationship.json +9 -0
- data/spec/fixtures/requested_by.json +12 -0
- data/spec/fixtures/shayne.json +1 -0
- data/spec/fixtures/subscription.json +12 -0
- data/spec/fixtures/subscription_deleted.json +1 -0
- data/spec/fixtures/subscription_payload.json +14 -0
- data/spec/fixtures/subscriptions.json +22 -0
- data/spec/fixtures/tag.json +1 -0
- data/spec/fixtures/tag_recent_media.json +1 -0
- data/spec/fixtures/tag_search.json +1 -0
- data/spec/fixtures/unblock_user.json +8 -0
- data/spec/fixtures/unfollow_user.json +8 -0
- data/spec/fixtures/user_media_feed.json +1 -0
- data/spec/fixtures/user_search.json +1 -0
- data/spec/instagram/api_spec.rb +285 -0
- data/spec/instagram/client/comments_spec.rb +71 -0
- data/spec/instagram/client/embedding_spec.rb +36 -0
- data/spec/instagram/client/geography_spec.rb +37 -0
- data/spec/instagram/client/likes_spec.rb +66 -0
- data/spec/instagram/client/locations_spec.rb +127 -0
- data/spec/instagram/client/media_spec.rb +99 -0
- data/spec/instagram/client/subscriptions_spec.rb +174 -0
- data/spec/instagram/client/tags_spec.rb +79 -0
- data/spec/instagram/client/users_spec.rb +432 -0
- data/spec/instagram/client/utils_spec.rb +32 -0
- data/spec/instagram/client_spec.rb +23 -0
- data/spec/instagram/request_spec.rb +56 -0
- data/spec/instagram_spec.rb +109 -0
- data/spec/spec_helper.rb +71 -0
- metadata +302 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
module Instagram
|
2
|
+
class Client
|
3
|
+
# Defines methods related to comments
|
4
|
+
module Comments
|
5
|
+
# Returns a list of comments for a given media item ID
|
6
|
+
#
|
7
|
+
# @overload media_comments(id)
|
8
|
+
# @param id [Integer] An Instagram media item ID
|
9
|
+
# @return [Hashie::Mash] The requested comments.
|
10
|
+
# @example Returns a list of comments for the media item of ID 1234
|
11
|
+
# Instagram.media_comments(777)
|
12
|
+
# @format :json
|
13
|
+
# @authenticated true
|
14
|
+
#
|
15
|
+
# If getting this data of a protected user, you must be authenticated (and be allowed to see that user).
|
16
|
+
# @rate_limited true
|
17
|
+
# @see http://instagram.com/developer/endpoints/comments/#get_media_comments
|
18
|
+
def media_comments(id, *args)
|
19
|
+
response = get("media/#{id}/comments")
|
20
|
+
response
|
21
|
+
end
|
22
|
+
|
23
|
+
# Creates a comment for a given media item ID
|
24
|
+
#
|
25
|
+
# @overload create_media_comment(id, text)
|
26
|
+
# @param id [Integer] An Instagram media item ID
|
27
|
+
# @param text [String] The text of your comment
|
28
|
+
# @return [Hashie::Mash] The comment created.
|
29
|
+
# @example Creates a new comment on media item with ID 777
|
30
|
+
# Instagram.create_media_comment(777, "Oh noes!")
|
31
|
+
# @format :json
|
32
|
+
# @authenticated true
|
33
|
+
#
|
34
|
+
# If getting this data of a protected user, you must be authenticated (and be allowed to see that user).
|
35
|
+
# @rate_limited true
|
36
|
+
# @see http://instagram.com/developer/endpoints/comments/#post_media_comments
|
37
|
+
def create_media_comment(id, text, options={})
|
38
|
+
response = post("media/#{id}/comments", options.merge(:text => text), signature=true)
|
39
|
+
response
|
40
|
+
end
|
41
|
+
|
42
|
+
# Deletes a comment for a given media item ID
|
43
|
+
#
|
44
|
+
# @overload delete_media_comment(media_id, comment_id)
|
45
|
+
# @param media_id [Integer] An Instagram media item ID.
|
46
|
+
# @param comment_id [Integer] Your comment ID of the comment you wish to delete.
|
47
|
+
# @return [nil]
|
48
|
+
# @example Delete the comment with ID of 1234, on the media item with ID of 777
|
49
|
+
# Instagram.delete_media_comment(777, 1234)
|
50
|
+
# @format :json
|
51
|
+
# @authenticated true
|
52
|
+
#
|
53
|
+
# In order to remove a comment, you must be the owner of the comment, the media item, or both.
|
54
|
+
# @rate_limited true
|
55
|
+
# @see http://instagram.com/developer/endpoints/comments/#delete_media_comments
|
56
|
+
def delete_media_comment(media_id, comment_id, options={})
|
57
|
+
response = delete("media/#{media_id}/comments/#{comment_id}", options, signature=true)
|
58
|
+
response
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Instagram
|
2
|
+
class Client
|
3
|
+
# Defines methods related to embedding
|
4
|
+
module Embedding
|
5
|
+
# Returns information about the media associated with the given short link
|
6
|
+
#
|
7
|
+
# @overload oembed(url=nil, options={})
|
8
|
+
# @param url [String] An instagram short link
|
9
|
+
# @param options [Hash] A customizable set of options
|
10
|
+
# @option options [Integer] :maxheight Maximum height of returned media
|
11
|
+
# @option options [Integer] :maxwidth Maximum width of returned media
|
12
|
+
# @option options [Integer] :callback A JSON callback to be invoked
|
13
|
+
# @return [Hashie::Mash] Information about the media associated with given short link
|
14
|
+
# @example Return information about the media associated with http://instagr.am/p/BUG/
|
15
|
+
# Instagram.oembed(http://instagr.am/p/BUG/)
|
16
|
+
#
|
17
|
+
# @see http://instagram.com/developer/embedding/#oembed
|
18
|
+
# @format :json
|
19
|
+
# @authenticated false
|
20
|
+
# @rate_limited true
|
21
|
+
def oembed(*args)
|
22
|
+
url = args.first
|
23
|
+
return nil unless url
|
24
|
+
get("oembed?url=#{url}", {}, false, false, true)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Instagram
|
2
|
+
class Client
|
3
|
+
# Defines methods related to real-time geographies
|
4
|
+
module Geographies
|
5
|
+
# Returns a list of recent media items for a given real-time geography
|
6
|
+
#
|
7
|
+
# @overload geography_recent_media(id, options={})
|
8
|
+
# @param user [Integer] A geography ID from a real-time subscription.
|
9
|
+
# @param options [Hash] A customizable set of options.
|
10
|
+
# @option options [Integer] :count (nil) Limit the number of results returned
|
11
|
+
# @option options [Integer] :min_id (nil) Return media before this min_id
|
12
|
+
# @option options [Integer] :max_id (nil) Return media after this max_id
|
13
|
+
# @option options [Integer] :min_timestamp (nil) Return media after this UNIX timestamp
|
14
|
+
# @option options [Integer] :max_timestamp (nil) Return media before this UNIX timestamp
|
15
|
+
# @return [Hashie::Mash]
|
16
|
+
# @example Return a list of the most recent media items taken within a specific geography
|
17
|
+
# Instagram.geography_recent_media(514276)
|
18
|
+
# @see http://instagram.com/developer/endpoints/geographies/
|
19
|
+
# @format :json
|
20
|
+
# @authenticated false
|
21
|
+
# @rate_limited true
|
22
|
+
def geography_recent_media(id, *args)
|
23
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
24
|
+
response = get("geographies/#{id}/media/recent", options)
|
25
|
+
response
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Instagram
|
2
|
+
class Client
|
3
|
+
# Defines methods related to likes
|
4
|
+
module Likes
|
5
|
+
# Returns a list of users who like a given media item ID
|
6
|
+
#
|
7
|
+
# @overload media_likes(id)
|
8
|
+
# @param media [Integer] An Instagram media item ID
|
9
|
+
# @return [Hashie::Mash] A list of users.
|
10
|
+
# @example Returns a list of users who like the media item of ID 1234
|
11
|
+
# Instagram.media_likes(777)
|
12
|
+
# @format :json
|
13
|
+
# @authenticated true
|
14
|
+
#
|
15
|
+
# If getting this data of a protected user, you must be authenticated (and be allowed to see that user).
|
16
|
+
# @rate_limited true
|
17
|
+
# @see http://instagram.com/developer/endpoints/likes/#get_media_likes
|
18
|
+
def media_likes(id, *args)
|
19
|
+
response = get("media/#{id}/likes")
|
20
|
+
response
|
21
|
+
end
|
22
|
+
|
23
|
+
# Issues a like by the currently authenticated user, for a given media item ID
|
24
|
+
#
|
25
|
+
# @overload like_media(id, text)
|
26
|
+
# @param id [Integer] An Instagram media item ID
|
27
|
+
# @return [Hashie::Mash] Metadata
|
28
|
+
# @example Like media item with ID 777
|
29
|
+
# Instagram.like_media(777)
|
30
|
+
# @format :json
|
31
|
+
# @authenticated true
|
32
|
+
#
|
33
|
+
# If getting this data of a protected user, you must be authenticated (and be allowed to see that user).
|
34
|
+
# @rate_limited true
|
35
|
+
# @see http://instagram.com/developer/endpoints/likes/#post_likes
|
36
|
+
def like_media(id, options={})
|
37
|
+
response = post("media/#{id}/likes", options, signature=true)
|
38
|
+
response
|
39
|
+
end
|
40
|
+
|
41
|
+
# Removes the like on a givem media item ID for the currently authenticated user
|
42
|
+
#
|
43
|
+
# @overload unlike_media(id)
|
44
|
+
# @param media_id [Integer] An Instagram media item ID.
|
45
|
+
# @return [Hashie::Mash] Metadata
|
46
|
+
# @example Remove the like for the currently authenticated user on the media item with the ID of 777
|
47
|
+
# Instagram.unlike_media(777)
|
48
|
+
# @format :json
|
49
|
+
# @authenticated true
|
50
|
+
# @rate_limited true
|
51
|
+
# @see http://instagram.com/developer/endpoints/likes/#delete_likes
|
52
|
+
def unlike_media(id, options={})
|
53
|
+
response = delete("media/#{id}/likes", options, signature=true)
|
54
|
+
response
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Instagram
|
2
|
+
class Client
|
3
|
+
# Defines methods related to media items
|
4
|
+
module Locations
|
5
|
+
# Returns extended information of a given Instagram location
|
6
|
+
#
|
7
|
+
# @overload location(id)
|
8
|
+
# @param location [Integer] An Instagram location ID
|
9
|
+
# @return [Hashie::Mash] The requested location.
|
10
|
+
# @example Return extended information for the Instagram office
|
11
|
+
# Instagram.location(514276)
|
12
|
+
# @format :json
|
13
|
+
# @authenticated false
|
14
|
+
# @rate_limited true
|
15
|
+
# @see http://instagram.com/developer/endpoints/locations/#get_locations
|
16
|
+
def location(id, *args)
|
17
|
+
response = get("locations/#{id}")
|
18
|
+
response
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns a list of recent media items for a given Instagram location
|
22
|
+
#
|
23
|
+
# @overload location_recent_media(id, options={})
|
24
|
+
# @param user [Integer] An Instagram location ID.
|
25
|
+
# @param options [Hash] A customizable set of options.
|
26
|
+
# @option options [Integer] :max_timestamp (nil) Return media before this UNIX timestamp
|
27
|
+
# @option options [Integer] :max_id (nil) Returns results with an ID less than (that is, older than) or equal to the specified ID.
|
28
|
+
# @option options [Integer] :count (nil) Limits the number of results returned per page.
|
29
|
+
# @return [Hashie::Mash]
|
30
|
+
# @example Return a list of the most recent media items taken at the Instagram office
|
31
|
+
# Instagram.location_recent_media(514276)
|
32
|
+
# @see http://instagram.com/developer/endpoints/locations/#get_locations_media_recent
|
33
|
+
# @format :json
|
34
|
+
# @authenticated false
|
35
|
+
# @rate_limited true
|
36
|
+
def location_recent_media(id, *args)
|
37
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
38
|
+
response = get("locations/#{id}/media/recent", options)
|
39
|
+
response
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns Instagram locations within proximity of given lat,lng or Facebook Places ID
|
43
|
+
#
|
44
|
+
# @overload location_search(options={})
|
45
|
+
# @param facebook_places_id [String] A valid Facebook Places ID
|
46
|
+
# @param lat [String] A given latitude in decimal format
|
47
|
+
# @param lng [String] A given longitude in decimal format
|
48
|
+
# @option options [Integer] :count The number of media items to retrieve.
|
49
|
+
# @return [Hashie::Mash] location resultm object, #data is an Array.
|
50
|
+
# @example 1: Return a location with the Facebook Places ID = ()
|
51
|
+
# Instagram.location_search("3fd66200f964a520c5f11ee3") (Schiller's Liquor Bar, 131 Rivington St., NY, NY 10002)
|
52
|
+
# @example 2: Return locations around 37.7808851, -122.3948632 (164 S Park, SF, CA USA)
|
53
|
+
# Instagram.location_search("37.7808851", "-122.3948632")
|
54
|
+
# @see http://instagram.com/developer/endpoints/locations/#get_locations_search
|
55
|
+
# @format :json
|
56
|
+
# @authenticated false
|
57
|
+
# @rate_limited true
|
58
|
+
def location_search(*args)
|
59
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
60
|
+
case args.size
|
61
|
+
when 1
|
62
|
+
facebook_places_id = args.first
|
63
|
+
response = get('locations/search', options.merge(:facebook_places_id => facebook_places_id))
|
64
|
+
when 2
|
65
|
+
lat, lng = args
|
66
|
+
response = get('locations/search', options.merge(:lat => lat, :lng => lng))
|
67
|
+
when 3
|
68
|
+
lat, lng, distance = args
|
69
|
+
response = get('locations/search', options.merge(:lat => lat, :lng => lng, :distance => distance))
|
70
|
+
end
|
71
|
+
response
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Instagram
|
2
|
+
class Client
|
3
|
+
# Defines methods related to media items
|
4
|
+
module Media
|
5
|
+
# Returns extended information of a given media item
|
6
|
+
#
|
7
|
+
# @overload media_item(id)
|
8
|
+
# @param user [Integer] An Instagram media item ID
|
9
|
+
# @return [Hashie::Mash] The requested media item.
|
10
|
+
# @example Return extended information for media item 1234
|
11
|
+
# Instagram.media_item(1324)
|
12
|
+
# @format :json
|
13
|
+
# @authenticated false unless requesting media from a protected user
|
14
|
+
#
|
15
|
+
# If getting this data of a protected user, you must authenticate (and be allowed to see that user).
|
16
|
+
# @rate_limited true
|
17
|
+
# @see http://instagram.com/developer/endpoints/media/#get_media
|
18
|
+
def media_item(*args)
|
19
|
+
id = args.first || 'self'
|
20
|
+
response = get("media/#{id}")
|
21
|
+
response
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns extended information of a given media item
|
25
|
+
#
|
26
|
+
# @overload media_shortcode(shortcode)
|
27
|
+
# @param shortcode [String] An Instagram media item shortcode
|
28
|
+
# @return [Hashie::Mash] The requested media item.
|
29
|
+
# @example Return extended information for media item with shortcode 'D'
|
30
|
+
# Instagram.media_shortcode('D')
|
31
|
+
# @format none
|
32
|
+
# @authenticated false unless requesting media from a protected user
|
33
|
+
#
|
34
|
+
# If getting this data of a protected user, you must authenticate (and be allowed to see that user).
|
35
|
+
# @rate_limited true
|
36
|
+
# @see http://instagram.com/developer/endpoints/media/#get_media_by_shortcode
|
37
|
+
def media_shortcode(*args)
|
38
|
+
shortcode = args.first
|
39
|
+
response = get("media/shortcode/#{shortcode}", {}, false, false, true)
|
40
|
+
response
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns a list of the overall most popular media
|
44
|
+
#
|
45
|
+
# @overload media_popular(options={})
|
46
|
+
# @param options [Hash] A customizable set of options.
|
47
|
+
# @return [Hashie::Mash]
|
48
|
+
# @example Returns a list of the overall most popular media
|
49
|
+
# Instagram.media_popular
|
50
|
+
# @see http://instagram.com/developer/endpoints/media/#get_media_popular
|
51
|
+
# @format :json
|
52
|
+
# @authenticated false unless requesting it from a protected user
|
53
|
+
#
|
54
|
+
# If getting this data of a protected user, you must authenticate (and be allowed to see that user).
|
55
|
+
# @rate_limited true
|
56
|
+
def media_popular(*args)
|
57
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
58
|
+
id = args.first || "self"
|
59
|
+
response = get("media/popular", options)
|
60
|
+
response
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns media items within proximity of given lat,lng
|
64
|
+
#
|
65
|
+
# @param lat [String] A given latitude in decimal format
|
66
|
+
# @param lng [String] A given longitude in decimal format
|
67
|
+
# @param options [Hash] A customizable set of options.
|
68
|
+
# @option options [Integer] :count The number of media items to retrieve.
|
69
|
+
# @return [Hashie::Mash] A list of matching media
|
70
|
+
# @example Return media around 37.7808851, -122.3948632 (164 S Park, SF, CA USA)
|
71
|
+
# Instagram.media_search("37.7808851", "-122.3948632")
|
72
|
+
# @see http://instagram.com/developer/endpoints/media/#get_media_search
|
73
|
+
# @format :json
|
74
|
+
# @authenticated false
|
75
|
+
# @rate_limited true
|
76
|
+
def media_search(lat, lng, options={})
|
77
|
+
response = get('media/search', options.merge(:lat => lat, :lng => lng))
|
78
|
+
response
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'multi_json'
|
3
|
+
|
4
|
+
module Instagram
|
5
|
+
class Client
|
6
|
+
# Defines methods related to real-time
|
7
|
+
module Subscriptions
|
8
|
+
# Returns a list of active real-time subscriptions
|
9
|
+
#
|
10
|
+
# @overload subscriptions(options={})
|
11
|
+
# @return [Hashie::Mash] The list of subscriptions.
|
12
|
+
# @example Returns a list of subscriptions for the authenticated application
|
13
|
+
# Instagram.subscriptions
|
14
|
+
# @format :json
|
15
|
+
# @authenticated true
|
16
|
+
#
|
17
|
+
# Requires client_secret to be set on the client or passed in options
|
18
|
+
# @rate_limited true
|
19
|
+
# @see https://api.instagram.com/developer/realtime/
|
20
|
+
def subscriptions(options={})
|
21
|
+
response = get("subscriptions", options.merge(:client_secret => client_secret))
|
22
|
+
response
|
23
|
+
end
|
24
|
+
|
25
|
+
# Creates a real-time subscription
|
26
|
+
#
|
27
|
+
# @overload create_subscription(options={})
|
28
|
+
# @param options [Hash] A set of parameters
|
29
|
+
# @option options [String] :object The object you'd like to subscribe to (user, tag, location or geography)
|
30
|
+
# @option options [String] :callback_url The subscription callback URL
|
31
|
+
# @option options [String] :aspect The aspect of the object you'd like to subscribe to (in this case, "media").
|
32
|
+
# @option options [String, Integer] :object_id When specifying a location or tag use the location's ID or tag name respectively
|
33
|
+
# @option options [String, Float] :lat The center latitude of an area, used when subscribing to a geography object
|
34
|
+
# @option options [String, Float] :lng The center longitude of an area, used when subscribing to a geography object
|
35
|
+
# @option options [String, Integer] :radius The distance in meters you'd like to capture around a given point
|
36
|
+
# @overload create_subscription(object, callback_url, aspect="media", options={})
|
37
|
+
# @param object [String] The object you'd like to subscribe to (user, tag, location or geography)
|
38
|
+
# @param callback_url [String] The subscription callback URL
|
39
|
+
# @param aspect [String] The aspect of the object you'd like to subscribe to (in this case, "media").
|
40
|
+
# @param options [Hash] Addition options and parameters
|
41
|
+
# @option options [String, Integer] :object_id When specifying a location or tag use the location's ID or tag name respectively
|
42
|
+
# @option options [String, Float] :lat The center latitude of an area, used when subscribing to a geography object
|
43
|
+
# @option options [String, Float] :lng The center longitude of an area, used when subscribing to a geography object
|
44
|
+
# @option options [String, Integer] :radius The distance in meters you'd like to capture around a given point
|
45
|
+
#
|
46
|
+
# Note that we only support "media" at this time, but we might support other types of subscriptions in the future.
|
47
|
+
# @return [Hashie::Mash] The subscription created.
|
48
|
+
# @example Creates a new subscription to receive notifications for user media changes.
|
49
|
+
# Instagram.create_subscription("user", "http://example.com/instagram/callback")
|
50
|
+
# @format :json
|
51
|
+
# @authenticated true
|
52
|
+
#
|
53
|
+
# Requires client_secret to be set on the client or passed in options
|
54
|
+
# @rate_limited true
|
55
|
+
# @see https://api.instagram.com/developer/realtime/
|
56
|
+
def create_subscription(*args)
|
57
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
58
|
+
object = args.shift
|
59
|
+
callback_url = args.shift
|
60
|
+
aspect = args.shift
|
61
|
+
options.tap {|o|
|
62
|
+
o[:object] = object unless object.nil?
|
63
|
+
o[:callback_url] = callback_url unless callback_url.nil?
|
64
|
+
o[:aspect] = aspect || o[:aspect] || "media"
|
65
|
+
}
|
66
|
+
response = post("subscriptions", options.merge(:client_secret => client_secret), signature=true)
|
67
|
+
response
|
68
|
+
end
|
69
|
+
|
70
|
+
# Deletes a real-time subscription
|
71
|
+
#
|
72
|
+
# @overload delete_subscription(options={})
|
73
|
+
# @param options [Hash] Addition options and parameters
|
74
|
+
# @option options [Integer] :subscription_id The subscription's ID
|
75
|
+
# @option options [String] :object When specified will remove all subscriptions of this object type, unless an :object_id is also specified (user, tag, location or geography)
|
76
|
+
# @option options [String, Integer] :object_id When specifying :object, include an :object_id to only remove subscriptions of that object and object_id
|
77
|
+
# @overload delete_subscription(subscription_id, options={})
|
78
|
+
# @param subscription_id [Integer] The subscription's ID
|
79
|
+
# @param options [Hash] Addition options and parameters
|
80
|
+
# @option options [String] :object When specified will remove all subscriptions of this object type, unless an :object_id is also specified (user, tag, location or geography)
|
81
|
+
# @option options [String, Integer] :object_id When specifying :object, include an :object_id to only remove subscriptions of that object and object_id
|
82
|
+
# @return [Hashie::Mash]
|
83
|
+
# @example Deletes an application's user change subscription
|
84
|
+
# Instagram.delete_subscription(:object => "user")
|
85
|
+
# @format :json
|
86
|
+
# @authenticated true
|
87
|
+
#
|
88
|
+
# Requires client_secret to be set on the client or passed in options
|
89
|
+
# @rate_limited true
|
90
|
+
# @see https://api.instagram.com/developer/realtime/
|
91
|
+
def delete_subscription(*args)
|
92
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
93
|
+
subscription_id = args.first
|
94
|
+
options.merge!(:id => subscription_id) if subscription_id
|
95
|
+
response = delete("subscriptions", options.merge(:client_secret => client_secret), signature=true)
|
96
|
+
response
|
97
|
+
end
|
98
|
+
|
99
|
+
# As a security measure (to prevent DDoS attacks), Instagram sends a verification request to your server
|
100
|
+
# after you request a subscription.
|
101
|
+
# This method parses the challenge params and makes sure the call is legitimate.
|
102
|
+
#
|
103
|
+
# @param params the request parameters sent by Instagram. (You can pass in a Rails params hash.)
|
104
|
+
# @param verify_token the verify token sent in the {#subscribe subscription request}, if you provided one
|
105
|
+
#
|
106
|
+
# @yield verify_token if you need to compute the verification token
|
107
|
+
# (for instance, if your callback URL includes a record ID, which you look up
|
108
|
+
# and use to calculate a hash), you can pass meet_challenge a block, which
|
109
|
+
# will receive the verify_token received back from Instagram.
|
110
|
+
#
|
111
|
+
# @return the challenge string to be sent back to Instagram, or false if the request is invalid.
|
112
|
+
def meet_challenge(params, verify_token = nil, &verification_block)
|
113
|
+
if params["hub.mode"] == "subscribe" &&
|
114
|
+
# you can make sure this is legitimate through two ways
|
115
|
+
# if your store the token across the calls, you can pass in the token value
|
116
|
+
# and we'll make sure it matches
|
117
|
+
((verify_token && params["hub.verify_token"] == verify_token) ||
|
118
|
+
# alternately, if you sent a specially-constructed value (such as a hash of various secret values)
|
119
|
+
# you can pass in a block, which we'll call with the verify_token sent by Instagram
|
120
|
+
# if it's legit, return anything that evaluates to true; otherwise, return nil or false
|
121
|
+
(verification_block && yield(params["hub.verify_token"])))
|
122
|
+
params["hub.challenge"]
|
123
|
+
else
|
124
|
+
false
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Public: As a security measure, all updates from Instagram are signed using
|
129
|
+
# X-Hub-Signature: XXXX where XXX is the sha1 of the json payload
|
130
|
+
# using your application secret as the key.
|
131
|
+
#
|
132
|
+
# Example:
|
133
|
+
# # in Rails controller
|
134
|
+
# def receive_update
|
135
|
+
# if Instagram.validate_update(request.body, headers)
|
136
|
+
# ...
|
137
|
+
# else
|
138
|
+
# render text: "not authorized", status: 401
|
139
|
+
# end
|
140
|
+
# end
|
141
|
+
def validate_update(body, headers)
|
142
|
+
unless client_secret
|
143
|
+
raise ArgumentError, "client_secret must be set during configure"
|
144
|
+
end
|
145
|
+
|
146
|
+
if request_signature = headers['X-Hub-Signature'] || headers['HTTP_X_HUB_SIGNATURE']
|
147
|
+
calculated_signature = OpenSSL::HMAC.hexdigest('sha1', client_secret, body)
|
148
|
+
calculated_signature == request_signature
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Process a subscription notification JSON payload
|
153
|
+
#
|
154
|
+
# @overload process_subscription(json, &block)
|
155
|
+
# @param json [String] The JSON response received by the Instagram real-time server
|
156
|
+
# @param block [Proc] A callable in which callbacks are defined
|
157
|
+
# @option options [String] :signature Pass in an X-Hub-Signature to use for payload validation
|
158
|
+
# @return [nil]
|
159
|
+
# @example Process and handle a notification for a user media change
|
160
|
+
# Instagram.process_subscription(params[:body]) do |handler|
|
161
|
+
#
|
162
|
+
# handler.on_user_changed do |user_id, data|
|
163
|
+
#
|
164
|
+
# user = User.by_instagram_id(user_id)
|
165
|
+
# @client = Instagram.client(:access_token => _access_token_for_user(user))
|
166
|
+
# latest_media = @client.user_recent_media[0]
|
167
|
+
# user.media.create_with_hash(latest_media)
|
168
|
+
# end
|
169
|
+
#
|
170
|
+
# end
|
171
|
+
# @format :json
|
172
|
+
# @authenticated true
|
173
|
+
#
|
174
|
+
# Requires client_secret to be set on the client or passed in options
|
175
|
+
# @rate_limited true
|
176
|
+
# @see https://api.instagram.com/developer/realtime/
|
177
|
+
def process_subscription(json, options={}, &block)
|
178
|
+
raise ArgumentError, "callbacks block expected" unless block_given?
|
179
|
+
|
180
|
+
if options.has_key?(:signature)
|
181
|
+
if !client_secret
|
182
|
+
raise ArgumentError, "client_secret must be set during configure"
|
183
|
+
end
|
184
|
+
digest = OpenSSL::Digest.new('sha1')
|
185
|
+
verify_signature = OpenSSL::HMAC.hexdigest(digest, client_secret, json)
|
186
|
+
|
187
|
+
if options[:signature] != verify_signature
|
188
|
+
raise Instagram::InvalidSignature, "invalid X-Hub-Signature does not match verify signature against client_secret"
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
payload = MultiJson.decode(json)
|
193
|
+
@changes = Hash.new { |h,k| h[k] = [] }
|
194
|
+
for change in payload
|
195
|
+
@changes[change['object']] << change
|
196
|
+
end
|
197
|
+
block.call(self)
|
198
|
+
end
|
199
|
+
|
200
|
+
[:user, :tag, :location, :geography].each do |object|
|
201
|
+
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ +1
|
202
|
+
def on_#{object}_changed(&block)
|
203
|
+
for change in @changes['#{object}']
|
204
|
+
yield change.delete('object_id'), change
|
205
|
+
end
|
206
|
+
end
|
207
|
+
RUBY_EVAL
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|