garb 0.6.0 → 0.7.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.
- data/README.md +2 -1
- data/lib/garb/account.rb +2 -2
- data/lib/garb/data_request.rb +6 -5
- data/lib/garb/profile.rb +8 -7
- data/lib/garb/resource.rb +12 -8
- data/lib/garb/session.rb +17 -14
- data/lib/garb/version.rb +1 -1
- data/test/unit/garb/account_test.rb +16 -5
- data/test/unit/garb/data_request_test.rb +20 -16
- data/test/unit/garb/profile_test.rb +16 -12
- data/test/unit/garb/report_test.rb +2 -2
- data/test/unit/garb/resource_test.rb +19 -0
- data/test/unit/garb/session_test.rb +40 -0
- metadata +2 -2
data/README.md
CHANGED
@@ -193,8 +193,9 @@ SSL
|
|
193
193
|
TODOS
|
194
194
|
-----
|
195
195
|
|
196
|
-
* Sessions are currently global, which isn't awesome
|
197
196
|
* Read opensearch header in results
|
197
|
+
* Investigate new features from GA to see if they're in the API, implement if so
|
198
|
+
* clarify AND/OR filtering behavior in code and documentation
|
198
199
|
|
199
200
|
Requirements
|
200
201
|
------------
|
data/lib/garb/account.rb
CHANGED
@@ -8,10 +8,10 @@ module Garb
|
|
8
8
|
@profiles = profiles
|
9
9
|
end
|
10
10
|
|
11
|
-
def self.all
|
11
|
+
def self.all(session = Session)
|
12
12
|
# Profile.all.group_to_array{|p| p.account_id}.map{|profiles| new(profiles)}
|
13
13
|
|
14
|
-
profile_groups = Profile.all.inject({}) do |hash, profile|
|
14
|
+
profile_groups = Profile.all(session).inject({}) do |hash, profile|
|
15
15
|
key = profile.account_id
|
16
16
|
|
17
17
|
if hash.has_key?(key)
|
data/lib/garb/data_request.rb
CHANGED
@@ -2,7 +2,8 @@ module Garb
|
|
2
2
|
class DataRequest
|
3
3
|
class ClientError < StandardError; end
|
4
4
|
|
5
|
-
def initialize(base_url, parameters={})
|
5
|
+
def initialize(session, base_url, parameters={})
|
6
|
+
@session = session
|
6
7
|
@base_url = base_url
|
7
8
|
@parameters = parameters
|
8
9
|
end
|
@@ -17,9 +18,9 @@ module Garb
|
|
17
18
|
end
|
18
19
|
|
19
20
|
def send_request
|
20
|
-
response = if
|
21
|
+
response = if @session.single_user?
|
21
22
|
single_user_request
|
22
|
-
elsif
|
23
|
+
elsif @session.oauth_user?
|
23
24
|
oauth_user_request
|
24
25
|
end
|
25
26
|
|
@@ -31,11 +32,11 @@ module Garb
|
|
31
32
|
http = Net::HTTP.new(uri.host, uri.port)
|
32
33
|
http.use_ssl = true
|
33
34
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
34
|
-
http.get("#{uri.path}#{query_string}", 'Authorization' => "GoogleLogin auth=#{
|
35
|
+
http.get("#{uri.path}#{query_string}", 'Authorization' => "GoogleLogin auth=#{@session.auth_token}")
|
35
36
|
end
|
36
37
|
|
37
38
|
def oauth_user_request
|
38
|
-
|
39
|
+
@session.access_token.get("#{uri}#{query_string}")
|
39
40
|
end
|
40
41
|
end
|
41
42
|
end
|
data/lib/garb/profile.rb
CHANGED
@@ -3,7 +3,7 @@ module Garb
|
|
3
3
|
|
4
4
|
include ProfileReports
|
5
5
|
|
6
|
-
attr_reader :table_id, :title, :account_name, :account_id, :web_property_id
|
6
|
+
attr_reader :session, :table_id, :title, :account_name, :account_id, :web_property_id
|
7
7
|
|
8
8
|
class Property
|
9
9
|
include HappyMapper
|
@@ -30,7 +30,8 @@ module Garb
|
|
30
30
|
has_many :properties, Property
|
31
31
|
end
|
32
32
|
|
33
|
-
def initialize(entry)
|
33
|
+
def initialize(entry, session)
|
34
|
+
@session = session
|
34
35
|
@title = entry.title
|
35
36
|
@table_id = entry.tableId
|
36
37
|
|
@@ -43,14 +44,14 @@ module Garb
|
|
43
44
|
Garb.from_google_analytics(@table_id)
|
44
45
|
end
|
45
46
|
|
46
|
-
def self.all
|
47
|
+
def self.all(session = Session)
|
47
48
|
url = "https://www.google.com/analytics/feeds/accounts/default"
|
48
|
-
response = DataRequest.new(url).send_request
|
49
|
-
Entry.parse(response.body).map {|entry| new(entry)}
|
49
|
+
response = DataRequest.new(session, url).send_request
|
50
|
+
Entry.parse(response.body).map {|entry| new(entry, session)}
|
50
51
|
end
|
51
52
|
|
52
|
-
def self.first(id)
|
53
|
-
all.detect {|profile| profile.id == id || profile.web_property_id == id }
|
53
|
+
def self.first(id, session = Session)
|
54
|
+
all(session).detect {|profile| profile.id == id || profile.web_property_id == id }
|
54
55
|
end
|
55
56
|
end
|
56
57
|
end
|
data/lib/garb/resource.rb
CHANGED
@@ -41,16 +41,20 @@ module Garb
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def results(profile, opts = {}, &block)
|
44
|
-
@profile = profile.is_a?(Profile) ? profile : Profile.first(profile)
|
44
|
+
@profile = profile.is_a?(Profile) ? profile : Profile.first(profile, opts.fetch(:session, Session))
|
45
45
|
|
46
|
-
@
|
47
|
-
|
48
|
-
|
49
|
-
|
46
|
+
if @profile
|
47
|
+
@start_date = opts.fetch(:start_date, Time.now - MONTH)
|
48
|
+
@end_date = opts.fetch(:end_date, Time.now)
|
49
|
+
@limit = opts.fetch(:limit, nil)
|
50
|
+
@offset = opts.fetch(:offset, nil)
|
50
51
|
|
51
|
-
|
52
|
+
instance_eval(&block) if block_given?
|
52
53
|
|
53
|
-
|
54
|
+
ReportResponse.new(send_request_for_body).results
|
55
|
+
else
|
56
|
+
[]
|
57
|
+
end
|
54
58
|
end
|
55
59
|
|
56
60
|
def page_params
|
@@ -80,7 +84,7 @@ module Garb
|
|
80
84
|
end
|
81
85
|
|
82
86
|
def send_request_for_body
|
83
|
-
request = DataRequest.new(URL, params)
|
87
|
+
request = DataRequest.new(@profile.session, URL, params)
|
84
88
|
response = request.send_request
|
85
89
|
response.body
|
86
90
|
end
|
data/lib/garb/session.rb
CHANGED
@@ -1,22 +1,25 @@
|
|
1
1
|
module Garb
|
2
|
-
|
3
|
-
|
2
|
+
class Session
|
3
|
+
module Methods
|
4
|
+
attr_accessor :auth_token, :access_token, :email
|
4
5
|
|
5
|
-
|
6
|
+
# use only for single user authentication
|
7
|
+
def login(email, password, opts={})
|
8
|
+
self.email = email
|
9
|
+
auth_request = AuthenticationRequest.new(email, password, opts)
|
10
|
+
self.auth_token = auth_request.auth_token(opts)
|
11
|
+
end
|
6
12
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
auth_request = AuthenticationRequest.new(email, password, opts)
|
11
|
-
self.auth_token = auth_request.auth_token(opts)
|
12
|
-
end
|
13
|
+
def single_user?
|
14
|
+
auth_token && auth_token.is_a?(String)
|
15
|
+
end
|
13
16
|
|
14
|
-
|
15
|
-
|
17
|
+
def oauth_user?
|
18
|
+
!access_token.nil?
|
19
|
+
end
|
16
20
|
end
|
17
21
|
|
18
|
-
|
19
|
-
|
20
|
-
end
|
22
|
+
include Methods
|
23
|
+
extend Methods
|
21
24
|
end
|
22
25
|
end
|
data/lib/garb/version.rb
CHANGED
@@ -18,13 +18,24 @@ module Garb
|
|
18
18
|
end
|
19
19
|
|
20
20
|
context "An instance of the Account class" do
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
setup do
|
22
|
+
profile = stub(:account_id => '1111', :account_name => 'Blog 1')
|
23
|
+
@profiles = [profile,profile]
|
24
|
+
@account = Account.new(@profiles)
|
25
|
+
end
|
26
|
+
|
27
|
+
context "all" do
|
28
|
+
should "use an optional user session" do
|
29
|
+
session = Session.new
|
30
|
+
Garb::Profile.expects(:all).with(session).returns(@profiles)
|
31
|
+
|
32
|
+
accounts = Account.all(session)
|
33
|
+
assert_equal 1, accounts.size
|
34
|
+
assert_equal @profiles, accounts.first.profiles
|
26
35
|
end
|
36
|
+
end
|
27
37
|
|
38
|
+
context "when creating a new account from an array of profiles" do
|
28
39
|
should "take the account id from the first profile" do
|
29
40
|
assert_equal @profiles.first.account_id, @account.id
|
30
41
|
end
|
@@ -4,10 +4,14 @@ module Garb
|
|
4
4
|
class DataRequestTest < MiniTest::Unit::TestCase
|
5
5
|
|
6
6
|
context "An instance of the DataRequest class" do
|
7
|
+
setup do
|
8
|
+
@session = Session.new
|
9
|
+
@session.auth_token = 'abcdefg123456'
|
10
|
+
end
|
7
11
|
|
8
12
|
should "be able to build the query string from parameters" do
|
9
13
|
parameters = {'ids' => '12345', 'metrics' => 'country'}
|
10
|
-
data_request = DataRequest.new("", parameters)
|
14
|
+
data_request = DataRequest.new(@session, "", parameters)
|
11
15
|
|
12
16
|
query_string = data_request.query_string
|
13
17
|
|
@@ -19,7 +23,7 @@ module Garb
|
|
19
23
|
end
|
20
24
|
|
21
25
|
should "return an empty query string if parameters are empty" do
|
22
|
-
data_request = DataRequest.new("")
|
26
|
+
data_request = DataRequest.new(@session, "")
|
23
27
|
assert_equal "", data_request.query_string
|
24
28
|
end
|
25
29
|
|
@@ -27,16 +31,16 @@ module Garb
|
|
27
31
|
url = 'http://example.com'
|
28
32
|
expected = URI.parse('http://example.com')
|
29
33
|
|
30
|
-
assert_equal expected, DataRequest.new(url).uri
|
34
|
+
assert_equal expected, DataRequest.new(@session, url).uri
|
31
35
|
end
|
32
36
|
|
33
37
|
should "be able to send a request for a single user" do
|
34
|
-
|
38
|
+
@session.stubs(:single_user?).returns(true)
|
35
39
|
response = mock('Net::HTTPOK') do |m|
|
36
40
|
m.expects(:kind_of?).with(Net::HTTPSuccess).returns(true)
|
37
41
|
end
|
38
42
|
|
39
|
-
data_request = DataRequest.new('https://example.com/data', 'key' => 'value')
|
43
|
+
data_request = DataRequest.new(@session, 'https://example.com/data', 'key' => 'value')
|
40
44
|
data_request.stubs(:single_user_request).returns(response)
|
41
45
|
data_request.send_request
|
42
46
|
|
@@ -44,13 +48,13 @@ module Garb
|
|
44
48
|
end
|
45
49
|
|
46
50
|
should "be able to send a request for an oauth user" do
|
47
|
-
|
48
|
-
|
51
|
+
@session.stubs(:single_user?).returns(false)
|
52
|
+
@session.stubs(:oauth_user?).returns(true)
|
49
53
|
response = mock('Net::HTTPOK') do |m|
|
50
54
|
m.expects(:kind_of?).with(Net::HTTPSuccess).returns(true)
|
51
55
|
end
|
52
56
|
|
53
|
-
data_request = DataRequest.new('https://example.com/data', 'key' => 'value')
|
57
|
+
data_request = DataRequest.new(@session, 'https://example.com/data', 'key' => 'value')
|
54
58
|
data_request.stubs(:oauth_user_request).returns(response)
|
55
59
|
data_request.send_request
|
56
60
|
|
@@ -58,11 +62,11 @@ module Garb
|
|
58
62
|
end
|
59
63
|
|
60
64
|
should "raise if the request is unauthorized" do
|
61
|
-
|
62
|
-
|
65
|
+
@session.stubs(:single_user?).returns(false)
|
66
|
+
@session.stubs(:oauth_user?).returns(true)
|
63
67
|
response = mock('Net::HTTPUnauthorized', :body => 'Error')
|
64
68
|
|
65
|
-
data_request = DataRequest.new('https://example.com/data', 'key' => 'value')
|
69
|
+
data_request = DataRequest.new(@session, 'https://example.com/data', 'key' => 'value')
|
66
70
|
data_request.stubs(:oauth_user_request).returns(response)
|
67
71
|
|
68
72
|
assert_raises(Garb::DataRequest::ClientError) do
|
@@ -72,17 +76,17 @@ module Garb
|
|
72
76
|
|
73
77
|
should "be able to request via the ouath access token" do
|
74
78
|
access_token = stub(:get => "responseobject")
|
75
|
-
|
79
|
+
@session.stubs(:access_token).returns(access_token)
|
76
80
|
|
77
|
-
data_request = DataRequest.new('https://example.com/data', 'key' => 'value')
|
81
|
+
data_request = DataRequest.new(@session, 'https://example.com/data', 'key' => 'value')
|
78
82
|
assert_equal 'responseobject', data_request.oauth_user_request
|
79
83
|
|
80
|
-
assert_received(
|
84
|
+
assert_received(@session, :access_token)
|
81
85
|
assert_received(access_token, :get) {|e| e.with('https://example.com/data?key=value')}
|
82
86
|
end
|
83
87
|
|
84
88
|
should "be able to request via http with an auth token" do
|
85
|
-
|
89
|
+
@session.expects(:auth_token).with().returns('toke')
|
86
90
|
response = mock
|
87
91
|
|
88
92
|
http = mock do |m|
|
@@ -93,7 +97,7 @@ module Garb
|
|
93
97
|
|
94
98
|
Net::HTTP.expects(:new).with('example.com', 443).returns(http)
|
95
99
|
|
96
|
-
data_request = DataRequest.new('https://example.com/data', 'key' => 'value')
|
100
|
+
data_request = DataRequest.new(@session, 'https://example.com/data', 'key' => 'value')
|
97
101
|
assert_equal response, data_request.single_user_request
|
98
102
|
end
|
99
103
|
end
|
@@ -4,6 +4,7 @@ module Garb
|
|
4
4
|
class ProfileTest < MiniTest::Unit::TestCase
|
5
5
|
|
6
6
|
context "The Profile class" do
|
7
|
+
setup {@session = Session.new}
|
7
8
|
|
8
9
|
should "be able to return a list of all profiles" do
|
9
10
|
url = 'https://www.google.com/analytics/feeds/accounts/default'
|
@@ -13,7 +14,7 @@ module Garb
|
|
13
14
|
data_request = mock
|
14
15
|
data_request.expects(:send_request).with().returns(stub(:body => xml))
|
15
16
|
|
16
|
-
DataRequest.expects(:new).with(url).returns(data_request)
|
17
|
+
DataRequest.expects(:new).with(@session, url).returns(data_request)
|
17
18
|
|
18
19
|
entries = [stub]
|
19
20
|
|
@@ -23,10 +24,10 @@ module Garb
|
|
23
24
|
entries.each do |entry|
|
24
25
|
profile = stub
|
25
26
|
profiles << profile
|
26
|
-
Garb::Profile.expects(:new).with(entry).returns(profile)
|
27
|
+
Garb::Profile.expects(:new).with(entry, @session).returns(profile)
|
27
28
|
end
|
28
29
|
|
29
|
-
assert_equal profiles, Profile.all
|
30
|
+
assert_equal profiles, Profile.all(@session)
|
30
31
|
end
|
31
32
|
|
32
33
|
should "return the first profile for a given web property id" do
|
@@ -36,7 +37,9 @@ module Garb
|
|
36
37
|
|
37
38
|
Garb::Profile.stubs(:all).returns(entries)
|
38
39
|
|
39
|
-
assert_equal profile1, Garb::Profile.first('12345')
|
40
|
+
assert_equal profile1, Garb::Profile.first('12345', @session)
|
41
|
+
|
42
|
+
assert_received(Garb::Profile, :all) {|e| e.with(@session)}
|
40
43
|
end
|
41
44
|
|
42
45
|
should "return the first profile for a given table id" do
|
@@ -46,25 +49,27 @@ module Garb
|
|
46
49
|
|
47
50
|
Garb::Profile.stubs(:all).returns(entries)
|
48
51
|
|
49
|
-
assert_equal profile2, Garb::Profile.first('67890')
|
52
|
+
assert_equal profile2, Garb::Profile.first('67890', @session)
|
53
|
+
|
54
|
+
assert_received(Garb::Profile, :all) {|e| e.with(@session)}
|
50
55
|
end
|
51
56
|
end
|
52
|
-
|
57
|
+
|
53
58
|
context "An instance of the Profile class" do
|
54
|
-
|
59
|
+
|
55
60
|
setup do
|
56
61
|
@entry = (Profile::Entry.parse(read_fixture('profile_feed.xml'))).first
|
57
|
-
@profile = Profile.new(@entry)
|
62
|
+
@profile = Profile.new(@entry, Session)
|
58
63
|
end
|
59
|
-
|
64
|
+
|
60
65
|
should "have a value for :title" do
|
61
66
|
assert_equal "Historical", @profile.title
|
62
67
|
end
|
63
|
-
|
68
|
+
|
64
69
|
should "have a value for :table_id" do
|
65
70
|
assert_equal 'ga:12345', @profile.table_id
|
66
71
|
end
|
67
|
-
|
72
|
+
|
68
73
|
should "have a value for :id" do
|
69
74
|
assert_equal '12345', @profile.id
|
70
75
|
end
|
@@ -76,7 +81,6 @@ module Garb
|
|
76
81
|
should "have a value for :account_name" do
|
77
82
|
assert_equal 'Blog Beta', @profile.account_name
|
78
83
|
end
|
79
|
-
|
80
84
|
end
|
81
85
|
|
82
86
|
end
|
@@ -7,7 +7,7 @@ module Garb
|
|
7
7
|
setup do
|
8
8
|
@now = Time.now
|
9
9
|
Time.stubs(:now).returns(@now)
|
10
|
-
@profile = stub(:table_id => 'ga:1234')
|
10
|
+
@profile = stub(:table_id => 'ga:1234', :session => Session)
|
11
11
|
@report = Report.new(@profile)
|
12
12
|
end
|
13
13
|
|
@@ -64,7 +64,7 @@ module Garb
|
|
64
64
|
request = mock {|m| m.expects(:send_request).returns(response) }
|
65
65
|
@report.expects(:params).returns('params')
|
66
66
|
|
67
|
-
DataRequest.expects(:new).with(Garb::Report::URL, 'params').returns(request)
|
67
|
+
DataRequest.expects(:new).with(Session, Garb::Report::URL, 'params').returns(request)
|
68
68
|
assert_equal 'response body', @report.send_request_for_body
|
69
69
|
end
|
70
70
|
|
@@ -15,5 +15,24 @@ class ResourceTest < MiniTest::Unit::TestCase
|
|
15
15
|
|
16
16
|
assert_equal 'analytics', TestReport.results(profile)
|
17
17
|
end
|
18
|
+
|
19
|
+
should "get results from GA using a specific user session" do
|
20
|
+
profile = '123'
|
21
|
+
session = Garb::Session.new
|
22
|
+
TestReport.expects(:send_request_for_body).returns('xml')
|
23
|
+
Garb::ReportResponse.expects(:new).with('xml').returns(mock(:results => 'analytics'))
|
24
|
+
Garb::Profile.expects(:first).with(profile, session).returns(mock('Garb::Profile'))
|
25
|
+
|
26
|
+
assert_equal 'analytics', TestReport.results(profile, :session => session)
|
27
|
+
end
|
28
|
+
|
29
|
+
should "return an empty result set if profile is invalid" do
|
30
|
+
profile = '123'
|
31
|
+
TestReport.expects(:send_request_for_body).never
|
32
|
+
Garb::ReportResponse.expects(:new).never
|
33
|
+
|
34
|
+
Garb::Profile.expects(:first).returns(nil)
|
35
|
+
assert_equal [], TestReport.results(profile)
|
36
|
+
end
|
18
37
|
end
|
19
38
|
end
|
@@ -40,5 +40,45 @@ module Garb
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
+
context "A Session" do
|
44
|
+
setup do
|
45
|
+
@session = Session.new
|
46
|
+
end
|
47
|
+
|
48
|
+
should "be able retrieve an auth_token for a user" do
|
49
|
+
auth_request = mock {|m| m.expects(:auth_token).with({}).returns('toke') }
|
50
|
+
AuthenticationRequest.expects(:new).with('email', 'password', {}).returns(auth_request)
|
51
|
+
|
52
|
+
@session.login('email', 'password')
|
53
|
+
assert_equal 'toke', @session.auth_token
|
54
|
+
end
|
55
|
+
|
56
|
+
should "be able retrieve an auth_token for a user with secure ssl" do
|
57
|
+
opts = {:secure => true, :account_type => 'GOOGLE'}
|
58
|
+
auth_request = mock {|m| m.expects(:auth_token).with(opts).returns('toke') }
|
59
|
+
AuthenticationRequest.expects(:new).with('email', 'password', opts).returns(auth_request)
|
60
|
+
|
61
|
+
@session.login('email', 'password', opts)
|
62
|
+
assert_equal 'toke', @session.auth_token
|
63
|
+
end
|
64
|
+
|
65
|
+
should "retain the email address for this session" do
|
66
|
+
AuthenticationRequest.stubs(:new).returns(stub(:auth_token => 'toke'))
|
67
|
+
|
68
|
+
@session.login('email', 'password')
|
69
|
+
assert_equal 'email', @session.email
|
70
|
+
end
|
71
|
+
|
72
|
+
should "know if the Session is for a single user" do
|
73
|
+
@session.auth_token = "abcdefg1234567"
|
74
|
+
assert_equal true, @session.single_user?
|
75
|
+
end
|
76
|
+
|
77
|
+
should "know if the Session is for oauth" do
|
78
|
+
@session.access_token = 'some_oauth_access_token'
|
79
|
+
assert_equal true, @session.oauth_user?
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
43
83
|
end
|
44
84
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: garb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tony Pitale
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-02-
|
12
|
+
date: 2010-02-16 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|