ApiWrapperFor8x8 0.0.1 → 0.0.3
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.
- data/.gitignore +1 -0
- data/README.md +30 -1
- data/lib/ApiWrapperFor8x8.rb +1 -0
- data/lib/ApiWrapperFor8x8/agent.rb +2 -2
- data/lib/ApiWrapperFor8x8/agents.rb +13 -19
- data/lib/ApiWrapperFor8x8/channel.rb +11 -2
- data/lib/ApiWrapperFor8x8/connection.rb +20 -3
- data/lib/ApiWrapperFor8x8/error.rb +2 -0
- data/lib/ApiWrapperFor8x8/stats.rb +50 -0
- data/lib/ApiWrapperFor8x8/version.rb +1 -1
- data/spec/agent_spec.rb +11 -0
- data/spec/agents_spec.rb +3 -16
- data/spec/channel_spec.rb +1 -1
- data/spec/connection_spec.rb +5 -6
- data/spec/error_spec.rb +40 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/stats_spec.rb +39 -0
- metadata +7 -2
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -19,7 +19,36 @@ Or install it yourself as:
|
|
19
19
|
|
20
20
|
## Usage
|
21
21
|
|
22
|
-
|
22
|
+
###Setup
|
23
|
+
```ruby
|
24
|
+
@api_connection = ApiWrapperFor8x8::Connection.new({
|
25
|
+
:username => 'foo', # your username for 8x8
|
26
|
+
:password => 'bar' # your password for 8x8
|
27
|
+
})
|
28
|
+
```
|
29
|
+
|
30
|
+
###Params for each call
|
31
|
+
Date range: it has to be a iso8601 format and a string with comma separated, Ex "#{(Time.now-3600*24).iso8601,Time.now.iso8601}"
|
32
|
+
Timezone: it need to be following: list_of_timezone[http://en.wikipedia.org/wiki/List_of_zoneinfo_time_zones], Ex. America/Los_Angeles
|
33
|
+
It has more params, which can be seen on 8x8 site[http://www.8x8.com/Support/BusinessSupport/Documentation/VirtualContactCenterDocumentation/VirtualContactCenterStats.aspx]
|
34
|
+
|
35
|
+
###Channel
|
36
|
+
|
37
|
+
Get a list of channels
|
38
|
+
```ruby
|
39
|
+
@api_coonection.channel_list
|
40
|
+
```
|
41
|
+
|
42
|
+
Get a list of agnets
|
43
|
+
```ruby
|
44
|
+
@api_coonection.agent_list
|
45
|
+
```
|
46
|
+
|
47
|
+
Get a list of agnet details
|
48
|
+
```ruby
|
49
|
+
@api_coonection.agents_details({:d => 'YOUR DATE RANGE', :tz => 'YOUR TIMEZONE'}, {FILTER OPTIONS})
|
50
|
+
```
|
51
|
+
|
23
52
|
|
24
53
|
## Contributing
|
25
54
|
|
data/lib/ApiWrapperFor8x8.rb
CHANGED
@@ -2,30 +2,24 @@ module ApiWrapperFor8x8
|
|
2
2
|
module Agents
|
3
3
|
include ApiWrapperFor8x8::Agent
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
# Get a list of all the agents
|
6
|
+
#
|
7
|
+
def agent_list(filtered_options={})
|
8
|
+
get('/stats/agents.json', {}, filtered_options)
|
7
9
|
end
|
8
10
|
|
11
|
+
# Get all the details of agents
|
12
|
+
#
|
13
|
+
# Ex. Get details for date range of '2013-09-04T00:00:00-07:00,2013-09-04T23:59:59-07:00'
|
14
|
+
# and filtered with queue-name and agent-id
|
15
|
+
# @api_connection.agents_detail({:d => '2013-09-04T00:00:00-07:00,2013-09-04T23:59:59-07:00'},
|
16
|
+
# {"agent-id"=>"foo", "queue-name"=>"bar"})
|
9
17
|
def agents_detail(params={}, filtered_options={})
|
10
18
|
details = []
|
11
|
-
|
12
|
-
details
|
19
|
+
agent_list.each do |agent|
|
20
|
+
details.concat(agent_detail(agent['agent-id'], params, filtered_options))
|
13
21
|
end
|
14
|
-
details
|
22
|
+
details
|
15
23
|
end
|
16
|
-
|
17
|
-
def filtered_agents(agent_list, filtered_options)
|
18
|
-
if filtered_options.size == 0
|
19
|
-
return list
|
20
|
-
end
|
21
|
-
agent_list.select do |agent|
|
22
|
-
flag = true
|
23
|
-
filtered_options.each do |key, value|
|
24
|
-
flag = false unless (agent[key] && agent[key] == value)
|
25
|
-
end
|
26
|
-
flag
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
24
|
end
|
31
25
|
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
module ApiWrapperFor8x8
|
2
2
|
module Channel
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
# Get a list of channels
|
5
|
+
#
|
6
|
+
def channel_list(filtered_options={})
|
7
|
+
get "/stats/channels.json", {}, filtered_options
|
6
8
|
end
|
7
9
|
|
8
10
|
# Get one details on the channel
|
@@ -21,6 +23,13 @@ module ApiWrapperFor8x8
|
|
21
23
|
|
22
24
|
# It is easier for geting the sum of a value from the
|
23
25
|
# an array of records with the restriction you can set
|
26
|
+
#
|
27
|
+
# Ex. Get a sum of 'accepted-count' from channel_id: 1, date range
|
28
|
+
# , filtered_options, and queue-name
|
29
|
+
# @api_connection.channel_sum_x('accepted-count',
|
30
|
+
# 1,
|
31
|
+
# {:d => '2013-09-04T00:00:00-07:00,2013-09-04T23:59:59-07:00'},
|
32
|
+
# {"agent-id"=>"foo", "queue-name"=>"bar"}}
|
24
33
|
def channel_sum_x(x, guid=0, params_options={}, filtered_options={})
|
25
34
|
details = channel_details(guid, params_options, filtered_options)
|
26
35
|
sum = details.map {|detail| detail[x]}.inject(:+) if details
|
@@ -4,12 +4,13 @@ module ApiWrapperFor8x8
|
|
4
4
|
|
5
5
|
include ApiWrapperFor8x8::Channel
|
6
6
|
include ApiWrapperFor8x8::Agents
|
7
|
+
include ApiWrapperFor8x8::Stats
|
7
8
|
|
8
9
|
RECORDS_LIMIT = 50
|
9
10
|
MAX_TRY = 3
|
10
11
|
VALID_SEGMENT = ['channels', 'agents', 'statistics']
|
11
12
|
|
12
|
-
base_uri "
|
13
|
+
base_uri "https://na3.mycontactual.com/api"
|
13
14
|
format :json
|
14
15
|
|
15
16
|
def initialize(creds={})
|
@@ -20,9 +21,11 @@ module ApiWrapperFor8x8
|
|
20
21
|
end
|
21
22
|
|
22
23
|
def request(method, url, options={})
|
23
|
-
|
24
|
+
unless api_token_keys_valid?
|
25
|
+
raise ApiWrapperFor8x8::ResponseError.new(nil, "Please set username and password correctly")
|
26
|
+
end
|
24
27
|
options[:basic_auth] = @configuration
|
25
|
-
self.class.__send__(method, url, options)
|
28
|
+
parsed_response(self.class.__send__(method, url, options))
|
26
29
|
end
|
27
30
|
|
28
31
|
def api_token_keys_valid?
|
@@ -93,5 +96,19 @@ module ApiWrapperFor8x8
|
|
93
96
|
flag
|
94
97
|
end
|
95
98
|
end
|
99
|
+
|
100
|
+
def parsed_response(response)
|
101
|
+
if response.is_a? Net::HTTPResponse
|
102
|
+
unless response.is_a? Net::HTTPSuccess
|
103
|
+
raise ApiWrapperFor8x8::ResponseError.new(response)
|
104
|
+
end
|
105
|
+
JSON.parse(response.body)
|
106
|
+
else
|
107
|
+
unless response.success?
|
108
|
+
raise ApiWrapperFor8x8::ResponseError.new(response)
|
109
|
+
end
|
110
|
+
response.parsed_response
|
111
|
+
end
|
112
|
+
end
|
96
113
|
end
|
97
114
|
end
|
@@ -15,6 +15,8 @@ module ApiWrapperFor8x8
|
|
15
15
|
def common_solutions
|
16
16
|
if @response.code.to_i == 401
|
17
17
|
"Check your credentials and make sure they are correct and not expired"
|
18
|
+
elsif @response.code.to_i >= 500 && @response.code.to_i < 600
|
19
|
+
"Check the format of your json"
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module ApiWrapperFor8x8
|
2
|
+
module Stats
|
3
|
+
|
4
|
+
DEFAULT_STAT_ATTR = ["entered-count", "accepted-count", "abandoned-count", "time-waiting"]
|
5
|
+
# Since the api only aggregate the records by half an
|
6
|
+
# hour, so why not they have aggregate by hour
|
7
|
+
def stats_per_hour(url, params={}, filtered_opts={}, stats_attr=[])
|
8
|
+
raise ApiWrapperFor8x8::ResponseError.new({}, "Required date range!") unless params[:d]
|
9
|
+
if stats_attr.include?('queue-name') || stats_attr.include?('time-stamp')
|
10
|
+
raise ApiWrapperFor8x8::ResponseError.new({}, "Does not support queue-name or time-stamp as stat attribute")
|
11
|
+
end
|
12
|
+
|
13
|
+
stats = get(url, params, filtered_opts)
|
14
|
+
stats_attr = DEFAULT_STAT_ATTR if stats_attr.size == 0
|
15
|
+
times = params[:d].split(',')
|
16
|
+
start = Time.parse(times.first)
|
17
|
+
stop = Time.parse(times.last)
|
18
|
+
hash = {}
|
19
|
+
|
20
|
+
# init the hash object
|
21
|
+
(beginning_of_hour(start).to_i..end_of_hour(stop).to_i).step(3600) do |h|
|
22
|
+
hour = Time.at(h)
|
23
|
+
hour_key = hour.iso8601
|
24
|
+
hash[hour_key] = {}
|
25
|
+
hash[hour_key]['timestamp'] = hour
|
26
|
+
stats_attr.each { |key| hash[hour_key][key] = 0 }
|
27
|
+
end
|
28
|
+
|
29
|
+
# insert stats data to hash with timestamp as key
|
30
|
+
stats.each do |stat|
|
31
|
+
timestamp = stat["time-stamp"]
|
32
|
+
timekey = hash[timestamp] ? timestamp : (Time.parse(timestamp) - 1800).iso8601
|
33
|
+
stats_attr.each do |stat_attr|
|
34
|
+
stats_by_time = hash[timekey] || {}
|
35
|
+
stats_by_time[stat_attr] += stat[stat_attr] if stats_by_time[stat_attr] && stat[stat_attr]
|
36
|
+
end
|
37
|
+
end if stats
|
38
|
+
return hash.collect{ |key, value| value }
|
39
|
+
end
|
40
|
+
|
41
|
+
def beginning_of_hour(time)
|
42
|
+
Time.mktime(time.year, time.month, time.day, time.hour).send(Time.now.gmt? ? :gmt : :localtime)
|
43
|
+
end
|
44
|
+
|
45
|
+
def end_of_hour(time)
|
46
|
+
beginning_of_hour(time)+3600
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
data/spec/agent_spec.rb
CHANGED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Agent' do
|
4
|
+
describe "get_detail" do
|
5
|
+
it "should have call get with correct params" do
|
6
|
+
id = 0
|
7
|
+
expect(@api).to receive(:get).with("/stats/agents/#{id}/statistics.json", {}, {})
|
8
|
+
@api.agent_detail(id, {}, {})
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/spec/agents_spec.rb
CHANGED
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe ApiWrapperFor8x8::Agents do
|
4
4
|
describe "agent_list" do
|
5
5
|
it "should GET /stats/agents.json" do
|
6
|
-
@api.should_receive(:get).with('/stats/agents.json', {})
|
6
|
+
@api.should_receive(:get).with('/stats/agents.json', {}, {})
|
7
7
|
@api.agent_list
|
8
8
|
end
|
9
9
|
end
|
@@ -15,22 +15,9 @@ describe ApiWrapperFor8x8::Agents do
|
|
15
15
|
resp = {'statistics' => {'statistic' => agents}}
|
16
16
|
agent_details = [{'agent-id' => agent_id, 'accepted-count' => 23}]
|
17
17
|
@api.stub(:agent_list)
|
18
|
-
expect(@api).to receive(:
|
19
|
-
expect(@api).to receive(:
|
20
|
-
expect(@api).to receive(:agent_detail).with(agent_id, {}).and_return(agent_details)
|
18
|
+
expect(@api).to receive(:agent_list).and_return(agents)
|
19
|
+
expect(@api).to receive(:agent_detail).with(agent_id, {}, {}).and_return(agent_details)
|
21
20
|
@api.agents_detail.should == agent_details
|
22
21
|
end
|
23
22
|
end
|
24
|
-
|
25
|
-
describe "filtered_agents" do
|
26
|
-
before :each do
|
27
|
-
@agent1 = {"agent-id" => "a", "enabled" => 'Y'}
|
28
|
-
@agent2 = {"agent-id" => 'b', "enabled" => 'D'}
|
29
|
-
@agent_lists = [@agent1, @agent2]
|
30
|
-
end
|
31
|
-
it "should filter agents with enabled" do
|
32
|
-
@api.filtered_agents(@agent_lists, {"enabled" => "Y"}).should == [@agent1]
|
33
|
-
@api.filtered_agents(@agent_lists, {"enabled" => "D"}).should == [@agent2]
|
34
|
-
end
|
35
|
-
end
|
36
23
|
end
|
data/spec/channel_spec.rb
CHANGED
@@ -8,7 +8,7 @@ describe ApiWrapperFor8x8::Channel do
|
|
8
8
|
|
9
9
|
describe "channel_list" do
|
10
10
|
it "should GET /stats/channels.json" do
|
11
|
-
@api.should_receive(:get).with('/stats/channels.json', {})
|
11
|
+
@api.should_receive(:get).with('/stats/channels.json', {}, {})
|
12
12
|
@api.channel_list
|
13
13
|
end
|
14
14
|
|
data/spec/connection_spec.rb
CHANGED
@@ -81,12 +81,11 @@ describe ApiWrapperFor8x8::Connection do
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
@api.get(url)
|
84
|
+
describe "base_uri" do
|
85
|
+
it "should not be empty or nil" do
|
86
|
+
ApiWrapperFor8x8::Connection::base_uri.should_not be_nil
|
87
|
+
ApiWrapperFor8x8::Connection::base_uri.size.should_not be_zero
|
88
|
+
end
|
90
89
|
end
|
91
90
|
|
92
91
|
end
|
data/spec/error_spec.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ApiWrapperFor8x8::ResponseError do
|
4
|
+
describe "For OAth response" do
|
5
|
+
before do
|
6
|
+
@net_http_response = Net::HTTPSuccess.new('1.1', '200', 'OK')
|
7
|
+
@error = ApiWrapperFor8x8::ResponseError.new(@net_http_response)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "response should return Net::HTTP response" do
|
11
|
+
@error.response.should == @net_http_response
|
12
|
+
end
|
13
|
+
|
14
|
+
it "code should return response code" do
|
15
|
+
@error.code.should == '200'
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "message" do
|
19
|
+
it "should return response message" do
|
20
|
+
@error.message.should == 'OK'
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should return specified message" do
|
24
|
+
error = ApiWrapperFor8x8::ResponseError.new(@net_http_response, "No way")
|
25
|
+
error.message.should == 'No way'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
describe "common_solutions" do
|
31
|
+
describe "on 401" do
|
32
|
+
it "should suggest to check credentials" do
|
33
|
+
net_http_response = Net::HTTPUnauthorized.new('1.1', '401', 'Unauthorized Access')
|
34
|
+
error = ApiWrapperFor8x8::ResponseError.new(net_http_response)
|
35
|
+
error.common_solutions.should match /Check your credentials/i
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/stats_spec.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "ApiWrapperFor8x8::Stats" do
|
4
|
+
describe "stats_per_hour" do
|
5
|
+
|
6
|
+
context "should return correct data with valid params" do
|
7
|
+
before :each do
|
8
|
+
@url = "/stats/channels/1/statistics.json"
|
9
|
+
@params = {:d => '2013-05-28T12:54:55-07:00,2013-05-28T19:54:55-07:00', :tz => 'America/Los_Angeles'}
|
10
|
+
@resp = [{"time-stamp" => "2013-05-28T13:30:00-07:00",
|
11
|
+
"entered-count" => 3,
|
12
|
+
"accepted-count" => 2,
|
13
|
+
"abandoned-count" => 1,
|
14
|
+
"time-waiting" => 24
|
15
|
+
},{"time-stamp" => "2013-05-28T14:00:00-07:00",
|
16
|
+
"entered-count" => 10,
|
17
|
+
"accepted-count" => 8,
|
18
|
+
"abandoned-count" => 2,
|
19
|
+
"time-waiting" => 124},
|
20
|
+
{"time-stamp" => "2013-05-28T19:00:00-07:00",
|
21
|
+
"entered-count" => 20,
|
22
|
+
"accepted-count" => 19,
|
23
|
+
"abandoned-count" => 1,
|
24
|
+
"time-waiting" => 144}]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return an array of hash that includes all the stat attr and the timestamp" do
|
28
|
+
expect(@api).to receive(:get).with(@url, @params, {}).and_return(@resp)
|
29
|
+
ret = @api.stats_per_hour(@url, @params, {})
|
30
|
+
|
31
|
+
ret.size.should == 9
|
32
|
+
ret.map {|r| r['entered-count']}.inject {|sum,num| sum+num}.should == 33
|
33
|
+
ret.map {|r| r['accepted-count']}.inject {|sum,num| sum+num}.should == 29
|
34
|
+
ret.map {|r| r['abandoned-count']}.inject {|sum,num| sum+num}.should == 4
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ApiWrapperFor8x8
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-09-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -143,13 +143,16 @@ files:
|
|
143
143
|
- lib/ApiWrapperFor8x8/channel.rb
|
144
144
|
- lib/ApiWrapperFor8x8/connection.rb
|
145
145
|
- lib/ApiWrapperFor8x8/error.rb
|
146
|
+
- lib/ApiWrapperFor8x8/stats.rb
|
146
147
|
- lib/ApiWrapperFor8x8/version.rb
|
147
148
|
- spec/.rspec
|
148
149
|
- spec/agent_spec.rb
|
149
150
|
- spec/agents_spec.rb
|
150
151
|
- spec/channel_spec.rb
|
151
152
|
- spec/connection_spec.rb
|
153
|
+
- spec/error_spec.rb
|
152
154
|
- spec/spec_helper.rb
|
155
|
+
- spec/stats_spec.rb
|
153
156
|
- spec/version_spec.rb
|
154
157
|
homepage: https://github.com/daifu/api-wrapper-for-8x8
|
155
158
|
licenses:
|
@@ -182,5 +185,7 @@ test_files:
|
|
182
185
|
- spec/agents_spec.rb
|
183
186
|
- spec/channel_spec.rb
|
184
187
|
- spec/connection_spec.rb
|
188
|
+
- spec/error_spec.rb
|
185
189
|
- spec/spec_helper.rb
|
190
|
+
- spec/stats_spec.rb
|
186
191
|
- spec/version_spec.rb
|