google_api 1.0.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +453 -0
- data/Rakefile +9 -0
- data/google_api.gemspec +22 -0
- data/lib/google_api.rb +37 -0
- data/lib/google_api/cache.rb +49 -0
- data/lib/google_api/configuration.rb +37 -0
- data/lib/google_api/core_ext/hash.rb +11 -0
- data/lib/google_api/core_ext/string.rb +13 -0
- data/lib/google_api/date.rb +59 -0
- data/lib/google_api/ga.rb +52 -0
- data/lib/google_api/ga/data.rb +335 -0
- data/lib/google_api/ga/data/data_dsl.rb +66 -0
- data/lib/google_api/ga/data/filters_dsl.rb +11 -0
- data/lib/google_api/ga/data/segment_dsl.rb +11 -0
- data/lib/google_api/ga/helper.rb +41 -0
- data/lib/google_api/ga/management/account.rb +37 -0
- data/lib/google_api/ga/management/goal.rb +58 -0
- data/lib/google_api/ga/management/management.rb +36 -0
- data/lib/google_api/ga/management/profile.rb +64 -0
- data/lib/google_api/ga/management/segment.rb +41 -0
- data/lib/google_api/ga/management/webproperty.rb +52 -0
- data/lib/google_api/ga/session.rb +165 -0
- data/lib/google_api/version.rb +3 -0
- data/spec/lib/google_api_spec.rb +63 -0
- data/spec/spec_helper.rb +8 -0
- metadata +125 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
module GoogleApi
|
2
|
+
module Ga
|
3
|
+
class DataDsl
|
4
|
+
|
5
|
+
OPERATORS = ['==', '!=', '>', '<', '>=', '<=', '=~', '!~']
|
6
|
+
OPERATORS_METHOD = {'%' => '=@', '**' => '!@'}
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@result = []
|
10
|
+
end
|
11
|
+
|
12
|
+
# Make operators
|
13
|
+
OPERATORS.each do |operator|
|
14
|
+
eval <<-METHOD
|
15
|
+
def #{operator} (value)
|
16
|
+
@result << @attribute + "#{operator}" + value.to_s
|
17
|
+
self
|
18
|
+
end
|
19
|
+
METHOD
|
20
|
+
end
|
21
|
+
OPERATORS_METHOD.each do |key, value|
|
22
|
+
eval <<-METHOD
|
23
|
+
def #{key} (value)
|
24
|
+
@result << @attribute + "#{value}" + value.to_s
|
25
|
+
self
|
26
|
+
end
|
27
|
+
METHOD
|
28
|
+
end
|
29
|
+
|
30
|
+
def method_missing(name)
|
31
|
+
if name.to_s =~ /\A[a-zA-Z0-9]+\Z/
|
32
|
+
@attribute = "ga:#{name}"
|
33
|
+
self
|
34
|
+
else
|
35
|
+
super
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def &(other)
|
40
|
+
@result << :and
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
def |(other)
|
45
|
+
@result << :or
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
def build_parameter
|
50
|
+
i = @result.index{ |x| x.is_a?(Symbol) }
|
51
|
+
|
52
|
+
if !i.nil?
|
53
|
+
result = @result[i-2] + (@result[i] == :and ? ";" : ",") + @result[i-1]
|
54
|
+
@result.delete_at(i)
|
55
|
+
@result.delete_at(i-1)
|
56
|
+
@result[i-2] = result
|
57
|
+
|
58
|
+
build_parameter
|
59
|
+
else
|
60
|
+
@result.join
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module GoogleApi
|
2
|
+
module Ga
|
3
|
+
module Helper
|
4
|
+
|
5
|
+
# Same as get but automaticly add day, month and year to dimension
|
6
|
+
#
|
7
|
+
# Also check cache
|
8
|
+
#
|
9
|
+
def get_by_day(parameters, start_date = prev_month, end_date = now, expire = nil)
|
10
|
+
|
11
|
+
[:dimensions, :sort].each do |param|
|
12
|
+
parameters[param] = [] unless parameters[param]
|
13
|
+
|
14
|
+
if parameters[param].is_a?(String) || parameters[param].is_a?(Symbol)
|
15
|
+
parameters[param] = [parameters[param]]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
parameters[:dimensions] << :day
|
20
|
+
|
21
|
+
if more_years?(start_date, end_date)
|
22
|
+
parameters[:dimensions] << :month
|
23
|
+
parameters[:dimensions] << :year
|
24
|
+
|
25
|
+
parameters[:sort] << :year
|
26
|
+
parameters[:sort] << :month
|
27
|
+
|
28
|
+
elsif more_months?(start_date, end_date)
|
29
|
+
parameters[:dimensions] << :month
|
30
|
+
|
31
|
+
parameters[:sort] << :month
|
32
|
+
end
|
33
|
+
|
34
|
+
parameters[:sort] << :day
|
35
|
+
|
36
|
+
get(parameters, start_date, end_date, expire)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module GoogleApi
|
2
|
+
module Ga
|
3
|
+
class Account < Management
|
4
|
+
|
5
|
+
def initialize(account)
|
6
|
+
set(account)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.all(account_id = '~all')
|
10
|
+
get({ accountId: account_id }).map { |account| Account.new(account) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.find(account_id)
|
14
|
+
all(account_id).first
|
15
|
+
end
|
16
|
+
|
17
|
+
def refresh
|
18
|
+
@webproperties = nil
|
19
|
+
|
20
|
+
set( Account.get({ accountId: @id }).first )
|
21
|
+
|
22
|
+
return true
|
23
|
+
end
|
24
|
+
|
25
|
+
def webproperties
|
26
|
+
@webproperties ||= Webproperty.all(@id)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def self.get(parameters = nil)
|
32
|
+
super(@@session.api.management.accounts.list, parameters)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module GoogleApi
|
2
|
+
module Ga
|
3
|
+
class Goal < Management
|
4
|
+
|
5
|
+
attr_reader :accountId
|
6
|
+
attr_reader :webPropertyId
|
7
|
+
attr_reader :profileId
|
8
|
+
attr_reader :value
|
9
|
+
attr_reader :active
|
10
|
+
attr_reader :type
|
11
|
+
attr_reader :goal
|
12
|
+
|
13
|
+
def initialize(goal)
|
14
|
+
set(goal)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.all(account_id = '~all', webproperty_id = '~all', profile_id = '~all', goal_id = '~all')
|
18
|
+
get({ accountId: account_id, webPropertyId: webproperty_id, profileId: profile_id, goalId: goal_id }).map { |goal| Goal.new(goal) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.find(goal_id)
|
22
|
+
all('~all', '~all', '~all', goal_id).first
|
23
|
+
end
|
24
|
+
|
25
|
+
def refresh
|
26
|
+
@profile = nil
|
27
|
+
|
28
|
+
set( Goal.get({ accountId: @accountId, webPropertyId: @id, profileId: @profileId, goalId: @id }).first )
|
29
|
+
|
30
|
+
return true
|
31
|
+
end
|
32
|
+
|
33
|
+
def profile
|
34
|
+
@profile ||= Profile.find(@profileId)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def self.get(parameters = nil)
|
40
|
+
super(@@session.api.management.goals.list, parameters)
|
41
|
+
end
|
42
|
+
|
43
|
+
def set(goal)
|
44
|
+
@accountId = goal['accountId']
|
45
|
+
@webPropertyId = goal['webPropertyId']
|
46
|
+
@profileId = goal['profileId']
|
47
|
+
@value = goal['value']
|
48
|
+
@active = goal['active']
|
49
|
+
@type = goal['type']
|
50
|
+
|
51
|
+
@goal = goal[camelize(@type) + 'Details']
|
52
|
+
|
53
|
+
super(goal)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module GoogleApi
|
2
|
+
module Ga
|
3
|
+
class Management
|
4
|
+
|
5
|
+
@@session = Session
|
6
|
+
|
7
|
+
attr_reader :id
|
8
|
+
attr_reader :name
|
9
|
+
attr_reader :created
|
10
|
+
attr_reader :updated
|
11
|
+
|
12
|
+
def camelize(string)
|
13
|
+
string = string.downcase.split('_').map!(&:capitalize).join
|
14
|
+
string[0] = string[0].downcase
|
15
|
+
string
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def self.get(api_method, parameters = nil)
|
21
|
+
JSON.parse(
|
22
|
+
@@session.client.execute(api_method: api_method,
|
23
|
+
parameters: parameters).body
|
24
|
+
)["items"]
|
25
|
+
end
|
26
|
+
|
27
|
+
def set(values)
|
28
|
+
@id = values['id']
|
29
|
+
@name = values['name']
|
30
|
+
@created = values['created']
|
31
|
+
@updated = values['updated']
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module GoogleApi
|
2
|
+
module Ga
|
3
|
+
class Profile < Management
|
4
|
+
|
5
|
+
attr_reader :accountId
|
6
|
+
attr_reader :webPropertyId
|
7
|
+
attr_reader :currency
|
8
|
+
attr_reader :timezone
|
9
|
+
|
10
|
+
def initialize(profile)
|
11
|
+
set(profile)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.all(account_id = '~all', webproperty_id = '~all', profile_id = '~all')
|
15
|
+
get({ accountId: account_id, webPropertyId: webproperty_id, profileId: '~all' }).map { |profile| Profile.new(profile) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.find(profile_id)
|
19
|
+
all('~all', '~all', profile_id).first
|
20
|
+
end
|
21
|
+
|
22
|
+
def refresh
|
23
|
+
@webproperty = nil
|
24
|
+
@goals = nil
|
25
|
+
|
26
|
+
set( Profile.get({ accountId: @accountId, webPropertyId: @webPropertyId, profileId: @id }).first )
|
27
|
+
|
28
|
+
return true
|
29
|
+
end
|
30
|
+
|
31
|
+
def webproperty
|
32
|
+
@webproperty ||= Webproperty.find(@webpropertyId)
|
33
|
+
end
|
34
|
+
|
35
|
+
def goals
|
36
|
+
@goals ||= Goal.all(@accountId, @webPropertyId, @id)
|
37
|
+
end
|
38
|
+
|
39
|
+
# def get(parameters, start_date = prev_month, end_date = now, expire = nil)
|
40
|
+
# Data.get(@id, parameters, start_date, end_date, expire)
|
41
|
+
# end
|
42
|
+
|
43
|
+
# def get!(parameters, start_date = prev_month, end_date = now)
|
44
|
+
# Data.get!(@id, parameters, start_date, end_date)
|
45
|
+
# end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def self.get(parameters = nil)
|
50
|
+
super(@@session.api.management.profiles.list, parameters)
|
51
|
+
end
|
52
|
+
|
53
|
+
def set(profile)
|
54
|
+
@accountId = profile['accountId']
|
55
|
+
@webPropertyId = profile['webPropertyId']
|
56
|
+
@currency = profile['currency']
|
57
|
+
@timezone = profile['timezone']
|
58
|
+
|
59
|
+
super(profile)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module GoogleApi
|
2
|
+
module Ga
|
3
|
+
class Segment < Management
|
4
|
+
|
5
|
+
attr_accessor :segmentId
|
6
|
+
attr_accessor :definition
|
7
|
+
|
8
|
+
def initialize(segment)
|
9
|
+
set(segment)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.all(segment_id = '~all')
|
13
|
+
get({ segmentId: segment_id }).map { |segment| Segment.new(segment) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.find(segment_id)
|
17
|
+
all(segment_id).first
|
18
|
+
end
|
19
|
+
|
20
|
+
def refresh
|
21
|
+
set( Segment.get({ segmentId: @id }).first )
|
22
|
+
|
23
|
+
return true
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def self.get(parameters = nil)
|
29
|
+
super(@@session.api.management.segments.list, parameters)
|
30
|
+
end
|
31
|
+
|
32
|
+
def set(segment)
|
33
|
+
@segmentId = segment['segmentId']
|
34
|
+
@definition = segment['definition']
|
35
|
+
|
36
|
+
super(segment)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module GoogleApi
|
2
|
+
module Ga
|
3
|
+
class Webproperty < Management
|
4
|
+
|
5
|
+
attr_reader :accountId
|
6
|
+
attr_reader :websiteUrl
|
7
|
+
|
8
|
+
def initialize(webproperty)
|
9
|
+
set(webproperty)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.all(account_id = '~all', webproperty_id = '~all')
|
13
|
+
get({ accountId: account_id, webPropertyId: webproperty_id }).map { |webproperty| Webproperty.new(webproperty) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.find(webproperty_id)
|
17
|
+
all('~all', webproperty_id).first
|
18
|
+
end
|
19
|
+
|
20
|
+
def refresh
|
21
|
+
@account = nil
|
22
|
+
@profiles = nil
|
23
|
+
|
24
|
+
set( Webproperty.get({ accountId: @accountId, webPropertyId: @id }).first )
|
25
|
+
|
26
|
+
return true
|
27
|
+
end
|
28
|
+
|
29
|
+
def account
|
30
|
+
@account ||= Account.find(@accountId)
|
31
|
+
end
|
32
|
+
|
33
|
+
def profiles
|
34
|
+
@profiles ||= Profile.all(@accountId, @id)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def self.get(parameters = nil)
|
40
|
+
super(@@session.api.management.webproperties.list, parameters)
|
41
|
+
end
|
42
|
+
|
43
|
+
def set(webproperty)
|
44
|
+
@accountId = webproperty['accountId']
|
45
|
+
@websiteUrl = webproperty['websiteUrl']
|
46
|
+
|
47
|
+
super(webproperty)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require "google_api/core_ext/string"
|
2
|
+
|
3
|
+
module GoogleApi
|
4
|
+
module Ga
|
5
|
+
|
6
|
+
class Session
|
7
|
+
|
8
|
+
SCOPE = "https://www.googleapis.com/auth/analytics.readonly"
|
9
|
+
NAME_API = "analytics"
|
10
|
+
VERSION_API = "v3"
|
11
|
+
|
12
|
+
@@api = nil
|
13
|
+
@@client = nil
|
14
|
+
|
15
|
+
# Config --------------------------------------------------------------------------------
|
16
|
+
|
17
|
+
def self._config
|
18
|
+
GoogleApi.config
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.client_id
|
22
|
+
_config.ga.client_id ? _config.ga.client_id : _config.client_id
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.client_secret
|
26
|
+
_config.ga.client_secret ? _config.ga.client_secret : _config.client_secret
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.redirect_uri
|
30
|
+
_config.ga.redirect_uri ? _config.ga.redirect_uri : _config.redirect_uri
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.client_cert_file
|
34
|
+
_config.ga.client_cert_file ? _config.ga.client_cert_file : _config.client_cert_file
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.client_developer_email
|
38
|
+
_config.ga.client_developer_email ? _config.ga.client_developer_email : _config.client_developer_email
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.key_secret
|
42
|
+
_config.ga.key_secret ? _config.ga.key_secret : _config.key_secret
|
43
|
+
end
|
44
|
+
|
45
|
+
# ---------------------------------------------------------------------------------------
|
46
|
+
|
47
|
+
def self.login_by_cert
|
48
|
+
@@client = Google::APIClient.new
|
49
|
+
|
50
|
+
key = Google::APIClient::PKCS12.load_key(client_cert_file, key_secret)
|
51
|
+
asserter = Google::APIClient::JWTAsserter.new(client_developer_email, SCOPE, key)
|
52
|
+
|
53
|
+
begin
|
54
|
+
@@client.authorization = asserter.authorize()
|
55
|
+
@@api = @@client.discovered_api(NAME_API, VERSION_API)
|
56
|
+
rescue
|
57
|
+
return false
|
58
|
+
end
|
59
|
+
|
60
|
+
return true
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.login_by_cert!
|
64
|
+
i = 0
|
65
|
+
while !login_by_cert
|
66
|
+
print "\r[#{Time.now.strftime("%H:%M:%S")}] ##{i += 1} ... \r".bold
|
67
|
+
sleep(1)
|
68
|
+
end
|
69
|
+
|
70
|
+
return true
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.login(code = nil)
|
74
|
+
@@client = Google::APIClient.new
|
75
|
+
@@client.authorization.client_id = client_id
|
76
|
+
@@client.authorization.client_secret = client_secret
|
77
|
+
@@client.authorization.scope = SCOPE
|
78
|
+
@@client.authorization.redirect_uri = redirect_uri
|
79
|
+
|
80
|
+
@@api = @@client.discovered_api(NAME_API, VERSION_API)
|
81
|
+
|
82
|
+
if code
|
83
|
+
@@client.authorization.code = code
|
84
|
+
|
85
|
+
begin
|
86
|
+
@@client.authorization.fetch_access_token!
|
87
|
+
rescue
|
88
|
+
return false
|
89
|
+
end
|
90
|
+
|
91
|
+
return true
|
92
|
+
else
|
93
|
+
@@client.authorization.authorization_uri.to_s
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.login_by_line(server = 'http://localhost/oauth2callback', port = 0)
|
98
|
+
require "launchy" # open browser
|
99
|
+
require "socket" # make tcp server
|
100
|
+
require "uri" # parse uri
|
101
|
+
|
102
|
+
uri = URI(server)
|
103
|
+
|
104
|
+
# Start webserver.
|
105
|
+
webserver = TCPServer.new(uri.host, port)
|
106
|
+
|
107
|
+
# By default port is 0. It means that TCPServer will get first free port.
|
108
|
+
# Port is required for redirect_uri.
|
109
|
+
uri.port = webserver.addr[1]
|
110
|
+
|
111
|
+
# Add redirect_uri for google oauth 2 callback.
|
112
|
+
GoogleApi.config.ga.redirect_uri = uri.to_s
|
113
|
+
|
114
|
+
# Open browser.
|
115
|
+
Launchy.open(login)
|
116
|
+
|
117
|
+
# Wait for new session.
|
118
|
+
session = webserver.accept
|
119
|
+
|
120
|
+
# Parse header for query.
|
121
|
+
request = session.gets.gsub(/GET\ \//, '').gsub(/\ HTTP.*/, '')
|
122
|
+
request = Hash[URI.decode_www_form(URI(request).query)]
|
123
|
+
|
124
|
+
code = request['code']
|
125
|
+
|
126
|
+
# Close session and webserver.
|
127
|
+
session.close
|
128
|
+
|
129
|
+
if login(code)
|
130
|
+
session.write("You have been successfully logged. Now you can close the browser.")
|
131
|
+
|
132
|
+
return true
|
133
|
+
end
|
134
|
+
|
135
|
+
session.write("You have not been logged. Please try again.")
|
136
|
+
|
137
|
+
return false
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.check_session!
|
141
|
+
if @@api.nil? || @@client.nil?
|
142
|
+
raise GoogleApi::SessionError, "You are not log in."
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.api
|
147
|
+
check_session!
|
148
|
+
|
149
|
+
@@api
|
150
|
+
end
|
151
|
+
|
152
|
+
def self.client
|
153
|
+
check_session!
|
154
|
+
|
155
|
+
if @@client.authorization.refresh_token && @@client.authorization.expired?
|
156
|
+
@@client.authorization.fetch_access_token!
|
157
|
+
end
|
158
|
+
|
159
|
+
@@client
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
end
|