garb 0.9.1 → 0.9.7
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.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +95 -0
- data/Gemfile +15 -0
- data/README.md +47 -25
- data/Rakefile +8 -34
- data/garb.gemspec +22 -0
- data/lib/garb.rb +71 -48
- data/lib/garb/attributes.rb +35 -0
- data/lib/garb/core_ext/array.rb +13 -0
- data/lib/garb/core_ext/string.rb +48 -0
- data/lib/garb/core_ext/symbol.rb +59 -0
- data/lib/garb/destination.rb +5 -6
- data/lib/garb/errors.rb +20 -0
- data/lib/garb/filter_parameters.rb +20 -29
- data/lib/garb/management/account.rb +10 -16
- data/lib/garb/management/feed.rb +4 -5
- data/lib/garb/management/goal.rb +10 -15
- data/lib/garb/management/profile.rb +11 -20
- data/lib/garb/management/segment.rb +9 -15
- data/lib/garb/management/web_property.rb +11 -16
- data/lib/garb/model.rb +37 -13
- data/lib/garb/path_attribute.rb +7 -0
- data/lib/garb/report_parameter.rb +5 -5
- data/lib/garb/report_response.rb +29 -28
- data/lib/garb/reports/bounces.rb +1 -1
- data/lib/garb/reports/exits.rb +1 -1
- data/lib/garb/reports/pageviews.rb +1 -1
- data/lib/garb/reports/unique_pageviews.rb +1 -1
- data/lib/garb/reports/visits.rb +1 -1
- data/lib/garb/request/authentication.rb +54 -0
- data/lib/garb/request/data.rb +98 -0
- data/lib/garb/result_set.rb +23 -9
- data/lib/garb/session.rb +3 -3
- data/lib/garb/step.rb +4 -4
- data/lib/garb/support.rb +6 -0
- data/lib/garb/version.rb +3 -3
- data/test/fixtures/account_management.json +1 -0
- data/test/fixtures/ga_profile_management.json +1 -0
- data/test/fixtures/ga_segment_management.json +1 -0
- data/test/fixtures/ga_webproperty_management.json +1 -0
- data/test/fixtures/goal_management.json +1 -0
- data/test/fixtures/profile_feed.json +1 -0
- data/test/fixtures/report_feed.json +75 -0
- data/test/test_helper.rb +6 -10
- data/test/unit/garb/filter_parameters_test.rb +15 -46
- data/test/unit/garb/management/account_test.rb +8 -16
- data/test/unit/garb/management/feed_test.rb +5 -10
- data/test/unit/garb/management/goal_test.rb +7 -21
- data/test/unit/garb/management/profile_test.rb +11 -26
- data/test/unit/garb/management/segment_test.rb +7 -6
- data/test/unit/garb/management/web_property_test.rb +10 -12
- data/test/unit/garb/model_test.rb +70 -32
- data/test/unit/garb/report_parameter_test.rb +6 -6
- data/test/unit/garb/report_response_test.rb +23 -13
- data/test/unit/garb/request/authentication_test.rb +152 -0
- data/test/unit/garb/request/data_test.rb +157 -0
- data/test/unit/garb/session_test.rb +13 -13
- data/test/unit/garb_test.rb +4 -11
- data/test/unit/symbol_operator_test.rb +3 -3
- metadata +90 -292
- data/lib/garb/account.rb +0 -22
- data/lib/garb/account_feed_request.rb +0 -25
- data/lib/garb/authentication_request.rb +0 -53
- data/lib/garb/data_request.rb +0 -42
- data/lib/garb/goal.rb +0 -20
- data/lib/garb/profile.rb +0 -33
- data/lib/garb/report.rb +0 -28
- data/lib/garb/resource.rb +0 -115
- data/lib/support.rb +0 -40
- data/test/unit/garb/account_feed_request_test.rb +0 -42
- data/test/unit/garb/account_test.rb +0 -53
- data/test/unit/garb/authentication_request_test.rb +0 -121
- data/test/unit/garb/coverage/assets/0.3.9/app.js +0 -66
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/blank.gif +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_close.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_loading.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_nav_left.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_nav_right.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_e.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_n.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_ne.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_nw.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_s.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_se.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_sw.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_shadow_w.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_title_left.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_title_main.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_title_over.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancy_title_right.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancybox-x.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancybox-y.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/fancybox.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.css +0 -363
- data/test/unit/garb/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.pack.js +0 -44
- data/test/unit/garb/coverage/assets/0.3.9/favicon.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/jquery-1.4.2.min.js +0 -155
- data/test/unit/garb/coverage/assets/0.3.9/jquery.dataTables.min.js +0 -152
- data/test/unit/garb/coverage/assets/0.3.9/jquery.timeago.js +0 -141
- data/test/unit/garb/coverage/assets/0.3.9/jquery.url.js +0 -174
- data/test/unit/garb/coverage/assets/0.3.9/loading.gif +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/magnify.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/test/unit/garb/coverage/assets/0.3.9/smoothness/jquery-ui-1.8.4.custom.css +0 -295
- data/test/unit/garb/coverage/assets/0.3.9/stylesheet.css +0 -341
- data/test/unit/garb/coverage/index.html +0 -100
- data/test/unit/garb/coverage/resultset.yml +0 -5
- data/test/unit/garb/data_request_test.rb +0 -107
- data/test/unit/garb/destination_test.rb +0 -28
- data/test/unit/garb/goal_test.rb +0 -24
- data/test/unit/garb/management/coverage/assets/0.3.9/app.js +0 -66
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/blank.gif +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_close.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_loading.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_nav_left.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_nav_right.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_e.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_n.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_ne.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_nw.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_s.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_se.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_sw.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_shadow_w.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_title_left.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_title_main.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_title_over.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancy_title_right.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancybox-x.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancybox-y.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/fancybox.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.css +0 -363
- data/test/unit/garb/management/coverage/assets/0.3.9/fancybox/jquery.fancybox-1.3.1.pack.js +0 -44
- data/test/unit/garb/management/coverage/assets/0.3.9/favicon.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/jquery-1.4.2.min.js +0 -155
- data/test/unit/garb/management/coverage/assets/0.3.9/jquery.dataTables.min.js +0 -152
- data/test/unit/garb/management/coverage/assets/0.3.9/jquery.timeago.js +0 -141
- data/test/unit/garb/management/coverage/assets/0.3.9/jquery.url.js +0 -174
- data/test/unit/garb/management/coverage/assets/0.3.9/loading.gif +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/magnify.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/test/unit/garb/management/coverage/assets/0.3.9/smoothness/jquery-ui-1.8.4.custom.css +0 -295
- data/test/unit/garb/management/coverage/assets/0.3.9/stylesheet.css +0 -341
- data/test/unit/garb/management/coverage/index.html +0 -100
- data/test/unit/garb/management/coverage/resultset.yml +0 -5
- data/test/unit/garb/profile_test.rb +0 -77
- data/test/unit/garb/report_test.rb +0 -99
- data/test/unit/garb/resource_test.rb +0 -50
- data/test/unit/garb/step_test.rb +0 -15
|
@@ -1,29 +1,24 @@
|
|
|
1
1
|
module Garb
|
|
2
2
|
module Management
|
|
3
3
|
class WebProperty
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
extend Attributes
|
|
5
|
+
include PathAttribute
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
attr_reader :session, :entry
|
|
8
|
+
ga_attribute :id, :name, :account_id, :website_url
|
|
9
|
+
|
|
10
|
+
def self.all(session = Session, path = '/accounts/~all/webproperties')
|
|
8
11
|
feed = Feed.new(session, path)
|
|
9
|
-
feed.entries.map {|entry|
|
|
12
|
+
feed.entries.map { |entry| new(entry, session) }
|
|
10
13
|
end
|
|
11
14
|
|
|
12
15
|
def self.for_account(account)
|
|
13
|
-
all(account.session, account.path+'/webproperties')
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def self.new_from_entry(entry, session)
|
|
17
|
-
web_property = new
|
|
18
|
-
web_property.session = session
|
|
19
|
-
web_property.path = Garb.parse_link(entry, "self").gsub(Feed::BASE_URL, '')
|
|
20
|
-
web_property.properties = Garb.parse_properties(entry)
|
|
21
|
-
web_property
|
|
16
|
+
all(account.session, account.path + '/webproperties')
|
|
22
17
|
end
|
|
23
18
|
|
|
24
|
-
def
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
def initialize(entry, session)
|
|
20
|
+
@entry = entry
|
|
21
|
+
@session = session
|
|
27
22
|
end
|
|
28
23
|
|
|
29
24
|
def profiles
|
data/lib/garb/model.rb
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
module Garb
|
|
2
2
|
module Model
|
|
3
3
|
MONTH = 2592000
|
|
4
|
-
URL =
|
|
4
|
+
URL = 'https://www.googleapis.com/analytics/v3/data/ga'
|
|
5
5
|
|
|
6
6
|
def self.extended(base)
|
|
7
7
|
ProfileReports.add_report_method(base)
|
|
8
|
+
# base.set_instance_klass(base)
|
|
8
9
|
end
|
|
9
10
|
|
|
10
11
|
def metrics(*fields)
|
|
@@ -26,8 +27,10 @@ module Garb
|
|
|
26
27
|
end
|
|
27
28
|
|
|
28
29
|
def results(profile, options = {})
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
return all_results(profile, options) if options.delete(:all)
|
|
31
|
+
|
|
32
|
+
start_date = options[:start_date] || Time.now - MONTH
|
|
33
|
+
end_date = options[:end_date] || Time.now
|
|
31
34
|
default_params = build_default_params(profile, start_date, end_date)
|
|
32
35
|
|
|
33
36
|
param_set = [
|
|
@@ -39,31 +42,49 @@ module Garb
|
|
|
39
42
|
parse_sort(options).to_params,
|
|
40
43
|
build_page_params(options)
|
|
41
44
|
]
|
|
42
|
-
|
|
43
45
|
data = send_request_for_data(profile, build_params(param_set))
|
|
44
46
|
ReportResponse.new(data, instance_klass).results
|
|
45
47
|
end
|
|
46
48
|
|
|
49
|
+
def all_results(profile, options = {})
|
|
50
|
+
options = options.dup
|
|
51
|
+
limit = options.delete(:limit)
|
|
52
|
+
options[:limit] = 10_000 # maximum allowed
|
|
53
|
+
results = nil
|
|
54
|
+
while ((rs = results(profile, options)) && !rs.empty?)
|
|
55
|
+
results = results ? results + rs : rs
|
|
56
|
+
options[:offset] = results.size + 1
|
|
57
|
+
|
|
58
|
+
break if limit && results.size >= limit
|
|
59
|
+
break if results.size >= results.total_results
|
|
60
|
+
end
|
|
61
|
+
limit && results ? results[0...limit] : results
|
|
62
|
+
end
|
|
63
|
+
|
|
47
64
|
private
|
|
48
65
|
def send_request_for_data(profile, params)
|
|
49
|
-
request =
|
|
66
|
+
request = Request::Data.new(profile.session, URL, params)
|
|
50
67
|
response = request.send_request
|
|
51
68
|
response.body
|
|
52
69
|
end
|
|
53
70
|
|
|
54
71
|
def build_params(param_set)
|
|
55
|
-
param_set.inject({}) {|p,i| p.merge
|
|
72
|
+
param_set.inject({}) { |p,i| p.merge i }.reject { |k,v| v.nil? }
|
|
56
73
|
end
|
|
57
74
|
|
|
58
75
|
def parse_filters(options)
|
|
59
|
-
|
|
60
|
-
filters.parameters << options[:filters] if options.has_key?(:filters)
|
|
61
|
-
filters
|
|
76
|
+
FilterParameters.new(options[:filters])
|
|
62
77
|
end
|
|
63
78
|
|
|
64
79
|
def parse_segment(options)
|
|
65
|
-
|
|
66
|
-
|
|
80
|
+
# dirty hack to support dynamic segments
|
|
81
|
+
if options.has_key?(:segment_id)
|
|
82
|
+
segment = "gaid::#{options[:segment_id]}"
|
|
83
|
+
elsif options.has_key?(:dynamic_segment)
|
|
84
|
+
filters = FilterParameters.new(options[:dynamic_segment])
|
|
85
|
+
segment = "dynamic::#{filters.to_params['filters']}"
|
|
86
|
+
end
|
|
87
|
+
{'segment' => segment}
|
|
67
88
|
end
|
|
68
89
|
|
|
69
90
|
def parse_sort(options)
|
|
@@ -81,11 +102,14 @@ module Garb
|
|
|
81
102
|
end
|
|
82
103
|
|
|
83
104
|
def build_page_params(options)
|
|
84
|
-
|
|
105
|
+
params = {}
|
|
106
|
+
params['max-results'] = options[:limit] if options.has_key? :limit
|
|
107
|
+
params['start-index'] = options[:offset] if options.has_key? :offset
|
|
108
|
+
params
|
|
85
109
|
end
|
|
86
110
|
|
|
87
111
|
def format_time(t)
|
|
88
112
|
t.strftime('%Y-%m-%d')
|
|
89
113
|
end
|
|
90
114
|
end
|
|
91
|
-
end
|
|
115
|
+
end
|
|
@@ -2,23 +2,23 @@ module Garb
|
|
|
2
2
|
class ReportParameter
|
|
3
3
|
|
|
4
4
|
attr_reader :elements
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
def initialize(name)
|
|
7
7
|
@name = name
|
|
8
8
|
@elements = []
|
|
9
9
|
end
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
def name
|
|
12
12
|
@name.to_s
|
|
13
13
|
end
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
def <<(element)
|
|
16
16
|
(@elements += [element].flatten).compact!
|
|
17
17
|
self
|
|
18
18
|
end
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
def to_params
|
|
21
|
-
value = self.elements.map{|param| Garb.to_google_analytics(param)}.join(',')
|
|
21
|
+
value = self.elements.map { |param| Garb.to_google_analytics(param) }.join(',')
|
|
22
22
|
value.empty? ? {} : {self.name => value}
|
|
23
23
|
end
|
|
24
24
|
end
|
data/lib/garb/report_response.rb
CHANGED
|
@@ -1,56 +1,57 @@
|
|
|
1
|
-
module Garb
|
|
1
|
+
module Garb
|
|
2
2
|
class ReportResponse
|
|
3
|
-
KEYS = ['dxp:metric', 'dxp:dimension']
|
|
4
3
|
|
|
5
4
|
def initialize(response_body, instance_klass = OpenStruct)
|
|
6
|
-
@
|
|
5
|
+
@response_body = response_body
|
|
7
6
|
@instance_klass = instance_klass
|
|
8
7
|
end
|
|
9
8
|
|
|
10
9
|
def results
|
|
11
10
|
if @results.nil?
|
|
12
11
|
@results = ResultSet.new(parse)
|
|
13
|
-
@results.total_results =
|
|
14
|
-
@results.sampled =
|
|
12
|
+
@results.total_results = total_results
|
|
13
|
+
@results.sampled = sampled?
|
|
15
14
|
end
|
|
16
|
-
|
|
17
15
|
@results
|
|
18
16
|
end
|
|
19
17
|
|
|
20
|
-
def
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
private
|
|
24
|
-
def parse
|
|
25
|
-
entries.map do |entry|
|
|
26
|
-
@instance_klass.new(Hash[
|
|
27
|
-
values_for(entry).map {|v| [Garb.from_ga(v['name']), v['value']]}
|
|
28
|
-
])
|
|
29
|
-
end
|
|
18
|
+
def total_results
|
|
19
|
+
data[:total_results]
|
|
30
20
|
end
|
|
31
21
|
|
|
32
|
-
def
|
|
33
|
-
|
|
22
|
+
def sampled?
|
|
23
|
+
data[:contains_sampled_data]
|
|
34
24
|
end
|
|
35
25
|
|
|
36
|
-
|
|
37
|
-
|
|
26
|
+
private
|
|
27
|
+
def keys
|
|
28
|
+
@keys ||= column_headers.map { |header| Garb.from_ga header['name'] }
|
|
38
29
|
end
|
|
39
30
|
|
|
40
|
-
def
|
|
41
|
-
|
|
31
|
+
def parse
|
|
32
|
+
rows.map do |row|
|
|
33
|
+
@instance_klass.new(Hash[*keys.zip(row).flatten])
|
|
34
|
+
end
|
|
42
35
|
end
|
|
43
36
|
|
|
44
|
-
def
|
|
45
|
-
|
|
37
|
+
def column_headers
|
|
38
|
+
data[:column_headers] || []
|
|
46
39
|
end
|
|
47
40
|
|
|
48
|
-
def
|
|
49
|
-
|
|
41
|
+
def rows
|
|
42
|
+
data[:rows] || []
|
|
50
43
|
end
|
|
51
44
|
|
|
52
|
-
def
|
|
53
|
-
|
|
45
|
+
def data
|
|
46
|
+
unless @data
|
|
47
|
+
@data = MultiJson.load @response_body
|
|
48
|
+
@data = @data.inject({}) do |data, pair|
|
|
49
|
+
key, value = pair
|
|
50
|
+
data[key.underscore.to_sym] = value
|
|
51
|
+
data
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
@data
|
|
54
55
|
end
|
|
55
56
|
end
|
|
56
57
|
end
|
data/lib/garb/reports/bounces.rb
CHANGED
data/lib/garb/reports/exits.rb
CHANGED
data/lib/garb/reports/visits.rb
CHANGED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Garb
|
|
2
|
+
module Request
|
|
3
|
+
class Authentication
|
|
4
|
+
URL = 'https://www.google.com/accounts/ClientLogin'
|
|
5
|
+
|
|
6
|
+
def initialize(email, password, opts = {})
|
|
7
|
+
@email = email
|
|
8
|
+
@password = password
|
|
9
|
+
@account_type = opts[:account_type] || 'HOSTED_OR_GOOGLE'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def parameters
|
|
13
|
+
{
|
|
14
|
+
'Email' => @email,
|
|
15
|
+
'Passwd' => @password,
|
|
16
|
+
'accountType' => @account_type,
|
|
17
|
+
'service' => 'analytics',
|
|
18
|
+
'source' => "sija-garb-v#{Garb::VERSION}"
|
|
19
|
+
}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def uri
|
|
23
|
+
@uri ||= URI.parse(URL)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def send_request(ssl_mode)
|
|
27
|
+
http = Net::HTTP.new(uri.host, uri.port, Garb.proxy_address, Garb.proxy_port)
|
|
28
|
+
http.open_timeout = Garb.open_timeout
|
|
29
|
+
http.read_timeout = Garb.read_timeout
|
|
30
|
+
http.use_ssl = true
|
|
31
|
+
http.verify_mode = ssl_mode
|
|
32
|
+
|
|
33
|
+
if ssl_mode == OpenSSL::SSL::VERIFY_PEER
|
|
34
|
+
http.ca_file = Garb.ca_cert_file
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
http.request(build_request) do |response|
|
|
38
|
+
raise AuthError unless response.is_a?(Net::HTTPOK)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def build_request
|
|
43
|
+
post = Net::HTTP::Post.new(uri.path)
|
|
44
|
+
post.set_form_data(parameters)
|
|
45
|
+
post
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def auth_token(opts = {})
|
|
49
|
+
ssl_mode = opts[:secure] ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
|
|
50
|
+
send_request(ssl_mode).body.match(/^Auth=(.*)$/)[1]
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
module Garb
|
|
2
|
+
module Request
|
|
3
|
+
class Data
|
|
4
|
+
def initialize(session, base_url, parameters = {})
|
|
5
|
+
@session, @base_url, @parameters = session, base_url, parameters
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def parameters
|
|
9
|
+
@parameters ||= {}
|
|
10
|
+
@parameters['key'] ||= @session.api_key unless @session.api_key.nil?
|
|
11
|
+
@parameters
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def query_string
|
|
15
|
+
params_list = parameters.map { |k, v| "#{k}=#{v}" }.join('&')
|
|
16
|
+
params_list.empty? ? '' : "?#{params_list}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def uri
|
|
20
|
+
@uri ||= URI.parse(@base_url)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def absolute_uri
|
|
24
|
+
uri.to_s + query_string
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def relative_uri
|
|
28
|
+
uri.path.to_s + query_string
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def send_request
|
|
32
|
+
Garb.log "Garb::Request -> #{relative_uri}"
|
|
33
|
+
|
|
34
|
+
response = if @session.single_user?
|
|
35
|
+
if Garb.use_fibers
|
|
36
|
+
single_user_request_evented
|
|
37
|
+
else
|
|
38
|
+
single_user_request
|
|
39
|
+
end
|
|
40
|
+
elsif @session.oauth_user?
|
|
41
|
+
oauth_user_request
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
Garb.log "Garb::Response -> #{response.inspect}"
|
|
45
|
+
handle_response response
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def handle_response(response)
|
|
49
|
+
unless response.kind_of?(Net::HTTPSuccess) || (response.respond_to?(:status) && response.status == 200)
|
|
50
|
+
body, parsed = response.body, MultiJson.load(response.body) rescue nil
|
|
51
|
+
if parsed and error = parsed['error']
|
|
52
|
+
klass = case error['code']
|
|
53
|
+
when 400 then BadRequestError
|
|
54
|
+
when 401 then InvalidCredentialsError
|
|
55
|
+
when 403 then InsufficientPermissionsError
|
|
56
|
+
when 503 then BackendError
|
|
57
|
+
else ClientError
|
|
58
|
+
end
|
|
59
|
+
raise klass.new(absolute_uri, error['message'], error['code'], error['errors'])
|
|
60
|
+
else
|
|
61
|
+
raise ClientError.new(absolute_uri, body)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
response
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def single_user_request_evented
|
|
68
|
+
f = Fiber.current
|
|
69
|
+
fiber = Fiber.new do
|
|
70
|
+
f.resume single_user_request
|
|
71
|
+
end
|
|
72
|
+
fiber.resume
|
|
73
|
+
Fiber.yield
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def single_user_request
|
|
77
|
+
http = Net::HTTP.new(uri.host, uri.port, Garb.proxy_address, Garb.proxy_port)
|
|
78
|
+
http.open_timeout = Garb.open_timeout
|
|
79
|
+
http.read_timeout = Garb.read_timeout
|
|
80
|
+
http.use_ssl = true
|
|
81
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
82
|
+
|
|
83
|
+
unless @session.access_token.nil?
|
|
84
|
+
http.request_get(relative_uri, {'Authorization' => "Bearer #{@session.access_token.token}"})
|
|
85
|
+
else
|
|
86
|
+
http.request_get(relative_uri, {
|
|
87
|
+
'Authorization' => "GoogleLogin auth=#{@session.auth_token}",
|
|
88
|
+
'GData-Version' => '3'
|
|
89
|
+
})
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def oauth_user_request
|
|
94
|
+
@session.access_token.get(absolute_uri, {'GData-Version' => '3'})
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|