Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ For more information about changelogs, check

* [FEATURE] Added `Fb::User`
* [FEATURE] Added `Fb::Page`
* [FEATURE] Added `Fb::Page#posts`
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,25 @@ user.email # => 'john.smith@example.com'
Fb::User#pages
--------------

Given an user access token with the `manage_pages` scope, you can get the list of Facebook pages managed by the user by calling:
Given an user access token with the `pages_show_list` scope, you can get the list of Facebook pages managed by the user by calling:

```ruby
user = Fb::User.new access_token: '--valid-access-token--'
user.pages
# => [#<Fb::Page: id="1234", name="sample1">, #<Fb::Page: id="5678", name="sample2">]
```

Fb::Page#posts
--------------

Given a page with posts, you can get the posts on the page since creation by calling:

```ruby
page = Fb::Page.new access_token: '--valid-access-token--'
page.posts
# => [#<Fb::Post: id="1234", type="video">, #<Fb::Post: id="5678", type="video">]
```

## Development

To run tests, obtain a long-term access token for a Facebook user who manages
Expand Down
3 changes: 3 additions & 0 deletions lib/fb/core.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
require 'fb/support'
require 'fb/paginated_request'
require 'fb/resource'
require 'fb/page'
require 'fb/user'
require 'fb/post'

# An object-oriented Ruby client for the Facebook Graph API.
# @see http://www.rubydoc.info/gems/fb-core/
Expand Down
2 changes: 1 addition & 1 deletion lib/fb/core/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ module Fb
class Core
# @return [String] the SemVer-compatible gem version.
# @see http://semver.org
VERSION = '1.0.0.alpha2'
VERSION = '1.0.0.alpha3'
end
end
16 changes: 15 additions & 1 deletion lib/fb/page.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Fb
# Provides methods to interact with Facebook pages through the Graph API.
# @see https://developers.facebook.com/docs/graph-api/reference/page/
class Page
class Page < Resource
# @option [String] the page’s unique ID.
attr_reader :id

Expand All @@ -15,10 +15,24 @@ class Page
# @option [String] :id The page’s unique ID.
# @option [String] :name The page’s name.
# @option [String] :category The page’s category.
# @option [String] :access_token an access token for the page.
def initialize(options = {})
@id = options[:id]
@name = options[:name]
@category = options[:category]
@access_token = options[:access_token]
end

# @return [Array<Fb::Post>] the posts published on the page.
def posts
@posts ||= begin
fields = %i(type created_time).join ','
params = {access_token: @access_token, limit: 100, fields: fields}
request = PaginatedRequest.new path: "/v2.9/#{@id}/posts", params: params
request.run.body['data'].map do |post_data|
Post.new symbolize_keys post_data
end
end
end

# @return [String] the representation of the page.
Expand Down
22 changes: 22 additions & 0 deletions lib/fb/paginated_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module Fb
# Provides a wrapper for HTTPRequest when the result has pagination links.
# @api private
class PaginatedRequest < HTTPRequest
# Sends the request and returns the response with the body parsed from JSON.
# If the response body contains a link to the next page, fetches that page
# as well and combines the data with the previous page.
# @return [Net::HTTPResponse] if the request succeeds.
# @raise [Fb::HTTPError] if the request fails.
def run
response = super
while after = response.body.dig('paging', 'cursors', 'after')
next_params = @params.merge after: after, limit: 100
next_request = HTTPRequest.new path: @path, params: next_params
next_body = next_request.run.body
response.body['paging'] = next_body['paging']
response.body['data'].concat next_body['data']
end
response
end
end
end
31 changes: 31 additions & 0 deletions lib/fb/post.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Ruby client to authenticate a Facebook user.
# @see http://www.rubydoc.info/gems/Fb/
module Fb
# Fb::Post reprensents a Facebook post. Post provides getters for:
# :id, :title, :url, :created_time, and :type.
class Post
# @option [String] the post’s unique ID.
attr_reader :id

# @option [String] the post’s type.
attr_reader :type

# @option [Time] the post’s creation time.
attr_reader :created_at

# @param [Hash] options the options to initialize an instance of Fb::Post.
# @option [String] :id the post id.
# @option [String] :type the post’s type.
# @option [String] :created_time the post’s creation time in iso8601 format.
def initialize(options = {})
@id = options[:id]
@type = options[:type]
@created_at = Time.parse(options[:created_time]) if options[:created_time]
end

# @return [String] the representation of the post.
def to_s
%Q(#<#{self.class.name} #{@id} "#{@type}">)
end
end
end
11 changes: 11 additions & 0 deletions lib/fb/resource.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Fb
# Provides a base class for Facebook resources (users, pages, ...)
class Resource
private
def symbolize_keys(hash)
{}.tap do |new_hash|
hash.each_key{|key| new_hash[key.to_sym] = hash[key]}
end
end
end
end
12 changes: 2 additions & 10 deletions lib/fb/user.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Fb
# Provides methods to interact with Facebook users through the Graph API.
# @see https://developers.facebook.com/docs/graph-api/reference/user/
class User
class User < Resource
# @param [Hash] options to initialize a User object.
# @option [String] :access_token an access token for the user.
def initialize(options = {})
Expand All @@ -23,17 +23,9 @@ def pages
params = {access_token: @access_token}
request = HTTPRequest.new path: '/me/accounts', params: params
request.run.body['data'].map do |page_data|
Page.new symbolize_keys(page_data)
Page.new symbolize_keys(page_data.merge access_token: @access_token)
end
end
end

private

def symbolize_keys(hash)
{}.tap do |new_hash|
hash.each_key{|key| new_hash[key.to_sym] = hash[key]}
end
end
end
end
24 changes: 24 additions & 0 deletions spec/page/posts_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
require 'spec_helper'

RSpec.describe 'Fb::Page#posts' do
context 'given an invalid access token' do
let(:page) { Fb::Page.new access_token: 'invalid_token' }

it 'raises Fb::HTTPError' do
expect{page.posts}.to raise_error Fb::HTTPError
end
end

context 'given a valid access_token' do
let(:user) { Fb::User.new access_token: ENV['FB_TEST_ACCESS_TOKEN'] }
let(:page) { user.pages.first }

it 'returns array of Post for any given page' do
expect(page.posts).to be_a(Array)
expect(page.posts).to all (be_a Fb::Post)
expect(page.posts.map &:id).to all(be_a String)
expect(page.posts.map &:type).to all(be_a String)
expect(page.posts.map &:created_at).to all(be_a Time)
end
end
end
16 changes: 16 additions & 0 deletions spec/paginated_request_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
require 'spec_helper'

RSpec.describe 'Fb::PaginatedRequest#run' do
let(:params) { {access_token: ENV['FB_TEST_ACCESS_TOKEN']} }
let(:request) { Fb::PaginatedRequest.new path: path, params: params }

context 'given a request which more than one page of results' do
let(:path) { '/v2.9/20531316728/posts' } # Posts by Facebook

it 'returns all the results, not just the first page' do
response = request.run
expect(response).to be_a Net::HTTPOK
expect(response.body['data'].size).to be > 100
end
end
end
9 changes: 9 additions & 0 deletions spec/post/to_s_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
require 'spec_helper'

RSpec.describe 'Fb::Post#to_s' do
let(:post) { Fb::Post.new id: 123, type: 'video' }

it 'returns a pretty string representation' do
expect(post.to_s).to eq '#<Fb::Post 123 "video">'
end
end