garb 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|