Skip to content

Commit 2afee28

Browse files
committed
Merge pull request #5 from kaneda/dev-rspecs-2
[dev-rspecs-2] Updates
2 parents aa6c82c + 294ea86 commit 2afee28

6 files changed

Lines changed: 236 additions & 47 deletions

File tree

lib/api/helpers/api_helpers.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ def has_data?(response)
3838
response.present? && response.body.present?
3939
end
4040

41-
def set_err(json_response)
41+
def set_err(response_code, json_response)
4242
if json_response.present?
4343
if json_response["error"].present?
4444
@error = json_response["error"]
4545
elsif json_response["code"].present?
46-
@error = get_error_message(response.code, json_response["code"])
46+
@error = get_error_message(response_code, json_response["code"])
4747
else
4848
@error = DEFAULT_ERR
4949
end
@@ -58,13 +58,15 @@ def parse_data(response)
5858
begin
5959
json_response = JSON.parse(response.body)
6060
rescue => e
61-
Rails.logger.error "Failed to parse JSON return from Buffer: #{e}"
61+
msg = "Failed to parse JSON return from Buffer: #{e}"
62+
log_or_print msg
63+
@error = msg
6264
end
6365

64-
if response.code == GOOD_RESPONSE
66+
if response.code == GOOD_RESPONSE || json_response.nil?
6567
return json_response
6668
else
67-
set_err(json_response)
69+
set_err(response.code, json_response)
6870
end
6971
end
7072

lib/api/user_api.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
class UserApi < BaseApi
44

55
# PATHS
6-
USER_PATH = "user.json"
6+
USER_PATH = "user.json"
7+
DEAUTH_PATH = "user/deauthorize.json"
78

89
def get_user_id
910
get_user_json["id"] rescue nil
@@ -13,4 +14,9 @@ def get_user_json
1314
return nil unless verify_token
1415
get_get_response( build_url(USER_PATH) )
1516
end
17+
18+
def deauthorize
19+
return nil unless verify_token
20+
get_get_response( build_url(DEAUTH_PATH) )
21+
end
1622
end

lib/buffer_client.rb

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ def get_user_json
8282
user_json
8383
end
8484

85+
def deauthorize
86+
success_json = @user_api.deauthorize
87+
record_err(@user_api)
88+
89+
is_success?(success_json)
90+
end
91+
8592
###############
8693
# PROFILE API #
8794
###############
@@ -108,6 +115,7 @@ def get_schedule(id)
108115
end
109116

110117
def update_schedule(id, sched_array)
118+
sched_array.deep_symbolize_keys!
111119
success_json = @profile_api.update_schedule(id, sched_array)
112120
record_err(@profile_api)
113121

@@ -153,7 +161,14 @@ def reorder_updates(id, updates_array, options = {})
153161
new_order_json = @update_api.reorder_updates(id, updates_array, options)
154162
record_err(@update_api)
155163

156-
new_order_json
164+
extract_key(new_order_json, "updates")
165+
end
166+
167+
def shuffle_updates(id, options = {})
168+
shuffle_json = @update_api.shuffle_updates(id, options)
169+
record_err(@update_api)
170+
171+
extract_key(shuffle_json, "updates")
157172
end
158173

159174
def create_update(profile_ids, options = {})
@@ -229,4 +244,8 @@ def is_success?(success_json)
229244
def record_err(api)
230245
@error = api.get_error if api.has_error?
231246
end
247+
248+
def extract_key(json, key)
249+
return json[key] if json.present?
250+
end
232251
end

readme.md

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,23 @@
11
# Buffer Gem
22

3-
Modelled after Octokit <3. This is a lightweight client for the Buffer API (https://buffer.com/developers/api), which is intended to return JSON as opposed to objects.
3+
Modelled after [Octokit](https://github.com/octokit/octokit.rb) <3, this is a lightweight client for the [Buffer API](https://buffer.com/developers/api), which is intended to return (mostly) JSON as opposed to objects.
44

55
[![Code Climate](https://codeclimate.com/github/kaneda/buffer-ruby/badges/gpa.svg)](https://codeclimate.com/github/kaneda/buffer-ruby)
66
[![Test Coverage](https://codeclimate.com/github/kaneda/buffer-ruby/badges/coverage.svg)](https://codeclimate.com/github/kaneda/buffer-ruby/coverage)
7+
[![Build Status](https://travis-ci.org/kaneda/buffer-ruby.svg?branch=master)](https://travis-ci.org/kaneda/buffer-ruby)
78

89
## Client API
910

1011
### What's Imlemented?
11-
* https://buffer.com/developers/api/oauth
12-
* https://buffer.com/developers/api/user
13-
* https://buffer.com/developers/api/profiles
14-
* https://buffer.com/developers/api/updates
15-
* https://buffer.com/developers/api/links
16-
* https://buffer.com/developers/api/info
17-
* https://buffer.com/developers/api/errors
18-
19-
20-
### What's Missing?
21-
* Rspecs
12+
* [OAuth](https://buffer.com/developers/api/oauth)
13+
* [Users](https://buffer.com/developers/api/user)
14+
* [Profiles](https://buffer.com/developers/api/profiles)
15+
* [Updates](https://buffer.com/developers/api/updates)
16+
* [Links](https://buffer.com/developers/api/links)
17+
* [Info](https://buffer.com/developers/api/info)
18+
* [Errors](https://buffer.com/developers/api/errors)
19+
* Automated builds through Travis-CI
20+
* Automated tests using RSpec
2221

2322
### Installing
2423

@@ -45,39 +44,39 @@ You can define the client up front or configure it later. The options array the
4544
buffer_client = BufferClient.new({
4645
:user_code => "yourcode"
4746
})
48-
```
4947

50-
```ruby
51-
buffer_client = BufferClient.new
48+
auth_tok = buffer_client.get_auth_token
5249

5350
buffer_client.configure({
54-
:user_code => "yourcode"
51+
:auth_token => auth_tok
5552
})
5653
```
5754

5855
### Available Calls
59-
| Client call | Input | Description | Notes
60-
| :---------: | :------ | :---- | :---------
61-
| get_auth_token | | Returns the user's long-lasting auth token | user_code must be defined in the buffer_client, as well as the ENV variables "BUFFER_KEY" and "BUFFER_SECRET" |
62-
| get_user_id | | Returns the user's Buffer ID | |
63-
| get_user_json | | Returns the entirety of the user JSON | |
64-
| get_user_profiles | | Returns the entirety of the profile JSON | |
65-
| get_user_profile | Profile ID | Get a single profile as JSON by ID | |
66-
| get_schedule | Profile ID | Get the schedule of a profile as JSON by ID | |
67-
| update_schedule | Profile ID, Schedule Hash | Set the schedule of a profile as JSON by ID | auth_token must be defined in the buffer client. See below for schedule representation |
68-
| get_update | Social Media Post ID | Gets an update by post ID | |
69-
| get_pending_updates | Profile ID, Options Hash (optional) | Gets pending updates as JSON by profile ID | Takes in hash of options, see Buffer API docs for optional parameters |
70-
| get_sent_updates | Profile ID, Options Hash (optional) | Gets sent updates as JSON by profile ID | Takes in hash of options, see Buffer API docs for optional parameters |
71-
| get_interactions | Social Media Post ID, Event, Options Hash (optional) | Gets interactions based on event type (see https://bufferapp.com/developers/api/info#configuration) | Takes in a hash of options, see Buffer API docs for optional parameters |
72-
| reorder_updates | Profile ID, Updates Array, Options Hash (optional) | Updates order of updates in a profile based on updates array | |
73-
| shuffle_updates | Profile ID, Options Hash (optional) | Randomize the order of updates to be sent | |
74-
| create_update | Profile ID Array, Options Hash (optional) | Create a new post | Note that for the "media" option, please specify each media option in the hash separately, e.g. ```{ "media[link]" => "http%3A%2F%2Fgoogle.com", "media[description]" => "The%20google%20homepage" }``` |
75-
| update_status | Social Media Post ID, Text, Options Hash (optional) | Update an existing status | For the "media" option see the note on create_update |
76-
| share_update | Social Media Post ID | Share a post immediately | |
77-
| destroy_update | Social Media Post ID| Permanently destroy an update | |
78-
| move_to_top | Social Media Post ID| Move post to top of queue | |
79-
| get_shares | URL (unencoded) | Gets the number of shares for a given URL through Buffer | You can pass a normal URL here, the client will encode it. This is one of the only calls to not require an auth_token |
80-
| get_configuration | | Gets the current Buffer config | |
56+
57+
| Client call | Input | Output | Notes
58+
| :---------: | :------ | :------ | :---------
59+
| [get_auth_token](https://buffer.com/developers/api/oauth) | | Auth Token:String | ENV variables "BUFFER_KEY" and "BUFFER_SECRET" must be defined here |
60+
| get_user_id | | ID:String | Convenience wrapper, calls get_user_json under the hood |
61+
| [get_user_json](https://buffer.com/developers/api/user#user) | | User:Hash | |
62+
| [deauthorize](https://buffer.com/developers/api/user#deauthorize) | | Success:Boolean | |
63+
| [get_user_profiles](https://buffer.com/developers/api/profiles#profiles) | | Profiles:Array<Hash> | |
64+
| [get_user_profile](https://buffer.com/developers/api/profiles#profilesid) | Profile ID:String | Profile:Hash | |
65+
| [get_schedule](https://buffer.com/developers/api/profiles#schedules) | Profile ID:String | Schedule:Hash | |
66+
| [update_schedule](https://buffer.com/developers/api/profiles#schedulesupdate) | Profile ID:String, Schedule:Hash | Success:Boolean | See below for schedule representation |
67+
| [get_update](https://buffer.com/developers/api/updates#updatesid) | Social Media Post ID:String | Update:Hash | |
68+
| [get_pending_updates](https://buffer.com/developers/api/updates#updatespending) | Profile ID:String, Options:Hash (optional) | UpdateResult:Hash | See Buffer API doc (link to the left) for optional parameters. "updates" key contains the Updates:Array<Hash> |
69+
| [get_sent_updates](https://buffer.com/developers/api/updates#updatessent) | Profile ID:String, Options:Hash (optional) | UpdateResult:Hash | See Buffer API doc (link to the left) for optional parameters. "updates" key contains the Updates:Array<Hash> |
70+
| [get_interactions](https://buffer.com/developers/api/updates#updatesinteractions) | Social Media Post ID:String, Event:ENUM, Options:Hash (optional) | Interactions:Hash | See [event types](https://bufferapp.com/developers/api/info#configuration) for possible event values and Buffer API doc (link to the left) for optional parameters. "interactions" key contains the Interactions:Array<Hash> |
71+
| [reorder_updates](https://buffer.com/developers/api/updates#updatesreorder) | Profile ID:String, Updates:Array, Options:Hash (optional) | Updates:Array<Hash> | |
72+
| [shuffle_updates](https://buffer.com/developers/api/updates#updatesshuffle) | Profile ID:String, Options:Hash (optional) | Updates:Array<Hash> | |
73+
| [create_update](https://buffer.com/developers/api/updates#updatescreate) | Profile IDs:Array, Options:Hash (optional) | Update:Hash | Note that for the "media" option, please specify each media option in the hash separately, e.g. ```{ "media[link]" => "http%3A%2F%2Fgoogle.com", "media[description]" => "The%20google%20homepage" }```. See all available options in the Buffer docs (link to the left) |
74+
| [update_status](https://buffer.com/developers/api/updates#updatesupdate) | Social Media Post ID:String, Text:String, Options:Hash (optional) | Update:Hash | For the "media" option see the note on create_update above |
75+
| [share_update](https://buffer.com/developers/api/updates#updatesshare) | Social Media Post ID:String | Success:Boolean | |
76+
| [destroy_update](https://buffer.com/developers/api/updates#updatesdestroy) | Social Media Post ID:String | Success:Boolean | |
77+
| [move_to_top](https://buffer.com/developers/api/updates#updatesmovetotop) | Social Media Post ID:String | Success:Boolean | |
78+
| [get_shares](https://buffer.com/developers/api/links#shares) | Unencodded URL:String | Shares:Integer | You can pass a normal URL here, the client will encode it. This is one of the only calls to not require an auth_token |
79+
| [get_configuration](https://buffer.com/developers/api/info#configuration) | | Configuration:Hash | "services" key has internal keys for each service |
8180

8281
### Helper methods
8382
| Method | Description |
@@ -104,20 +103,21 @@ To update a schedule the BufferClient is expecting a schedule of the form:
104103
]
105104
```
106105

106+
Note that you can make the keys symbols or strings, the client will accept either one.
107107
## Contributing
108108

109109
To contribute simply:
110110

111111
1. Fork this project
112112
2. Make your changes in a new branch
113113
3. Create a PR
114-
4. Once approved squash your commits (http://davidwalsh.name/squash-commits-git)
114+
4. Once approved [squash your commits](http://davidwalsh.name/squash-commits-git)
115115
5. Party
116116

117117
## Contact
118118

119119
120120

121-
Twitter: @kanedasan
121+
Twitter: [@kanedasan](https://twitter.com/kanedasan)
122122

123123
IRC: kaneda^ on FreeNode (##hackers)
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
require 'action_dispatch'
2+
require 'uri'
3+
require_relative '../../../../lib/api/helpers/api_helpers.rb'
4+
5+
describe ApiHelpers do
6+
let(:base_api) { build(:base_api) }
7+
let(:options) do
8+
{
9+
:key => "value",
10+
:key_2 => "value_2"
11+
}
12+
end
13+
14+
let(:err) { "An error" }
15+
16+
describe "#build_options_string" do
17+
let(:path_regex) do
18+
/\A(\w+=[\w\d]+(&\w+=[\w\d]+)+)*\Z/
19+
end
20+
21+
it "returns a string representing a valid path" do
22+
expect(base_api.build_options_string(options)).to match(path_regex)
23+
end
24+
end
25+
26+
describe "#build_url" do
27+
let(:path) { "some_path" }
28+
let(:auth_tok) { "123456789" }
29+
30+
it "returns a valid URL when given only a path" do
31+
expect(base_api.build_url(path, {}, false)).to match(URI::regexp)
32+
end
33+
34+
it "returns a valid URL when given a path and options" do
35+
expect(base_api.build_url(path, options, false)).to match(URI::regexp)
36+
end
37+
38+
it "returns a valid URL when given a path and an auth token" do
39+
base_api.instance_variable_set(:@auth_token, auth_tok)
40+
41+
expect(base_api.build_url(path)).to match(URI::regexp)
42+
end
43+
44+
it "returns a valid URL when given a path, options, and an auth token" do
45+
base_api.instance_variable_set(:@auth_token, auth_tok)
46+
47+
expect(base_api.build_url(path, options)).to match(URI::regexp)
48+
end
49+
end
50+
51+
describe "#set_err" do
52+
let(:response_code) { "403" }
53+
let(:err) { "An error" }
54+
let(:err_2) { "A second err" }
55+
let(:json_with_error) { { "error" => err } }
56+
let(:json_with_code) { { "code" => "1001" } }
57+
let(:json_with_other) { { "other" => "stuff" } }
58+
59+
it "returns the default error when response is blank" do
60+
expect(base_api.set_err(response_code, {})).to eq(ApiHelpers::DEFAULT_ERR)
61+
end
62+
63+
it "returns an error when the error key is present in the response" do
64+
expect(base_api.set_err(response_code, json_with_error)).to eq(err)
65+
end
66+
67+
it "returns another error when only the code key is present" do
68+
allow_any_instance_of(BaseApi).to receive(:get_error_message).and_return(err_2)
69+
expect(base_api.set_err(response_code, json_with_code)).to eq(err_2)
70+
end
71+
72+
it "returns the default error when response is present but neither error nor code is present" do
73+
expect(base_api.set_err(response_code, json_with_other)).to eq(ApiHelpers::DEFAULT_ERR)
74+
end
75+
end
76+
77+
describe "#has_data?" do
78+
let(:empty_response) do
79+
ActionDispatch::Response.new(500, {}, "")
80+
end
81+
82+
let(:valid_response) do
83+
ActionDispatch::Response.new(200, {}, "A body")
84+
end
85+
86+
it "returns false when passed a blank response" do
87+
expect(base_api.has_data?(empty_response)).to eq(false)
88+
end
89+
90+
it "returns true when passed a response with a body" do
91+
expect(base_api.has_data?(valid_response)).to eq(true)
92+
end
93+
end
94+
95+
describe "#parse_data" do
96+
let(:bad_json) { '{"foo": "bar"' }
97+
let(:bad_json_err) { "Failed to parse JSON return from Buffer" }
98+
let(:bad_response) do
99+
ActionDispatch::Response.new(403, {}, bad_json)
100+
end
101+
102+
let(:good_json) { "#{bad_json} }" }
103+
let(:good_response) do
104+
ActionDispatch::Response.new(200, {}, good_json)
105+
end
106+
107+
it "returns nil and sets @error if the response is invalid JSON" do
108+
json = base_api.parse_data(bad_response)
109+
expect(json).to be_nil
110+
expect(base_api.error).to include(bad_json_err)
111+
end
112+
113+
it "returns a hash when passed good JSON" do
114+
json = base_api.parse_data(good_response)
115+
expect(json).to be_present
116+
expect(json.is_a?(Hash)).to eq(true)
117+
end
118+
end
119+
120+
describe "#get_error_message" do
121+
let(:event_err) { "Event type not supported." }
122+
let(:http_code) { "400" }
123+
let(:err_code) { "1029" }
124+
125+
it "returns the event err when the given codes are passed" do
126+
expect(base_api.get_error_message(http_code, err_code)).to eq(event_err)
127+
end
128+
129+
it "returns the default error when the http code is unknown" do
130+
expect(base_api.get_error_message("10101", err_code)).to eq(ApiHelpers::DEFAULT_ERR)
131+
end
132+
133+
it "returns the default error when the error code is unknown" do
134+
expect(base_api.get_error_message(http_code, "10101")).to eq(ApiHelpers::DEFAULT_ERR)
135+
end
136+
end
137+
end

spec/lib/api/update_api_spec.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
require_relative '../../../lib/api/update_api.rb'
2+
3+
describe UpdateApi do
4+
let(:update_api) { build(:update_api) }
5+
let(:id) { "123456789" }
6+
let(:path) { "some_path" }
7+
8+
before(:each) do
9+
allow_any_instance_of(UpdateApi).to receive(:verify_token).and_return(true)
10+
end
11+
12+
describe "#build_profile_url" do
13+
it "returns a proper profile URL" do
14+
expected_val = "#{UpdateApi::PROFILE_PATH}/#{id}/#{path}"
15+
expect(update_api.send(:build_profile_url, id, path)).to include(expected_val)
16+
end
17+
end
18+
19+
describe "#build_update_url" do
20+
it "returns a proper update URL" do
21+
expected_val = "#{UpdateApi::UPDATE_PATH}/#{id}/#{path}"
22+
expect(update_api.send(:build_update_url, id, path)).to include(expected_val)
23+
end
24+
end
25+
end

0 commit comments

Comments
 (0)