gaapi 0.0.0alpha1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ed1eec8428af3796678e4689d89342be081a5d65
4
+ data.tar.gz: d2053bd9f3239fefdaf3f61b60006a7ed6812a8a
5
+ SHA512:
6
+ metadata.gz: 77e6411840c67a025016f15dd1f42222be5dcc57e5fde8470178236b4a7fc7fbe854ff56d49366535756f5af14009b6dcf9dc1fff2c49d38aab0bab9307805b7
7
+ data.tar.gz: 0f09fa129edc4792e5e3d8d30a705b410b16051ba75585560524d67b2a18c7c5bd13d88cd9a67354e97e584f49ff46b384ffffbb1450ad78b293ab807fc874ec
data/bin/gaapi ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), "..", "lib")
5
+ require "gaapi"
6
+
7
+ Main.call
data/lib/gaapi.rb ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # http://www.rubydoc.info/github/google/google-api-ruby-client/
4
+ require "google/apis/analyticsreporting_v4"
5
+ require "googleauth"
6
+ require "gaapi/main.rb"
7
+ require "gaapi/query.rb"
data/lib/gaapi/main.rb ADDED
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "optparse"
4
+
5
+ ##
6
+ # Basic runner for nginx config file generation.
7
+ module Main
8
+ class << self
9
+ def call
10
+ options = process_options
11
+
12
+ puts "options: #{options.inspect}" if options[:debug]
13
+
14
+ # return unless (result = Query.call(options))
15
+ query = Query.new((options[:query_file] || STDIN).read, options)
16
+
17
+ return if options[:dry_run]
18
+
19
+ result = query.execute
20
+
21
+ if result.code != "200"
22
+ puts "Request failed #{result.code}"
23
+ puts Query.pp(result.body)
24
+ return
25
+ end
26
+
27
+ case options[:output_format]
28
+ when :csv
29
+ puts Query.csv(result.body)
30
+ else
31
+ puts Query.pp(result.body)
32
+ end
33
+ end
34
+
35
+ def process_options
36
+ options = { credentials: File.join(Dir.home, ".gaapi/ga-api-key") }
37
+ opts = OptionParser.new do |opts|
38
+ opts.banner = "Usage: [options] VIEW_ID"
39
+ opts.accept(Date)
40
+
41
+ opts.on("-a TOKEN",
42
+ "--access-token TOKEN",
43
+ "An access token obtained from https://developers.google.com/oauthplayground.") do |access_token|
44
+ options[:access_token] = access_token
45
+ end
46
+
47
+ opts.on("--csv",
48
+ "Output result as a csv file.") do
49
+ options[:output_format] = :csv
50
+ end
51
+
52
+ opts.on("-c CREDENTIALS",
53
+ "--credentials CREDENTIALS",
54
+ "Location of the credentials file. Default: #{options[:credentials]}.") do |credentials|
55
+ options[:credentials] = credentials
56
+ end
57
+
58
+ opts.on("-d", "--debug", "Print debugging information.") do
59
+ options[:debug] = true
60
+ end
61
+
62
+ opts.on("-e",
63
+ "--end-date END_DATE",
64
+ Date,
65
+ "Report including END_DATE.") do |end_date|
66
+ options[:end_date] = end_date
67
+ end
68
+
69
+ opts.on("-n", "--dry-run", "Don't actually send the query to Google.") do
70
+ options[:dry_run] = true
71
+ end
72
+
73
+ opts.on("-q QUERYFILE",
74
+ "--query-file QUERYFILE",
75
+ "File containing the query. Default STDIN.") do |query_file|
76
+ options[:query_file] = File.open(query_file)
77
+ end
78
+
79
+ opts.on("-s",
80
+ "--start-date START_DATE",
81
+ Date,
82
+ "Report including START_DATE.") do |start_date|
83
+ options[:start_date] = start_date
84
+ end
85
+ end
86
+ opts.parse!
87
+ opts.abort("You must provide a view ID. \n" + opts.to_s) unless ARGV.size == 1
88
+ options[:view_id] = ARGV[0]
89
+
90
+ if options[:end_date].nil? && !options[:start_date].nil?
91
+ options[:end_date] = options[:start_date]
92
+ elsif options[:start_date].nil? && !options[:end_date].nil?
93
+ options[:start_date] = options[:end_date]
94
+ elsif options[:start_date].nil? && options[:end_date].nil?
95
+ options[:end_date] = options[:start_date] = (Date.today - 1).to_s
96
+ end
97
+
98
+ options
99
+ end
100
+ end
101
+ end
102
+
103
+ # Some hints:
104
+ # https://stackoverflow.com/a/41179467/3109926
105
+ # http://www.daimto.com/google-service-accounts-with-json-file/
106
+ # https://github.com/google/google-api-ruby-client/issues/489
107
+ # The above gave some progress.
@@ -0,0 +1,174 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "csv"
4
+ require "net/http"
5
+
6
+ class Query
7
+ class << self
8
+ def call(options)
9
+ # http://www.rubydoc.info/github/google/google-api-ruby-client/toplevel
10
+ # https://github.com/google/google-auth-library-ruby
11
+ scopes = %w[
12
+ https://www.googleapis.com/auth/analytics
13
+ https://www.googleapis.com/auth/analytics.readonly
14
+ ]
15
+
16
+ authorization = Google::Auth::ServiceAccountCredentials.make_creds(
17
+ json_key_io: File
18
+ .open(options[:credentials] || File.join(Dir.home,
19
+ ".ga-credentials/ga-api-key")),
20
+ scope: scopes
21
+ )
22
+
23
+ service = Google::Apis::AnalyticsreportingV4::AnalyticsReportingService.new
24
+ service.authorization = authorization
25
+
26
+ request = Google::Apis::AnalyticsreportingV4::ReportRequest.new(
27
+ view_id: options[:view_id],
28
+ date_ranges: [Google::Apis::AnalyticsreportingV4::DateRange.new(
29
+ start_date: options[:start_date],
30
+ end_date: options[:end_date]
31
+ )],
32
+ # dimensions: [
33
+ # Google::Apis::AnalyticsreportingV4::Dimension.new(name: "ga:segment")
34
+ # # Google::Apis::AnalyticsreportingV4::Dimension.new(name: "ga:adContent"),
35
+ # # Google::Apis::AnalyticsreportingV4::Dimension.new(name: "ga:campaign"),
36
+ # # Google::Apis::AnalyticsreportingV4::Dimension.new(name: "ga:keyword"),
37
+ # # Google::Apis::AnalyticsreportingV4::Dimension.new(name: "ga:medium"),
38
+ # # Google::Apis::AnalyticsreportingV4::Dimension.new(name: "ga:socialNetwork"),
39
+ # # Google::Apis::AnalyticsreportingV4::Dimension.new(name: "ga:source")
40
+ # ],
41
+ metrics: [
42
+ # Google::Apis::AnalyticsreportingV4::Metric.new(
43
+ # expression: "ga:bounces"
44
+ # ),
45
+ Google::Apis::AnalyticsreportingV4::Metric.new(
46
+ expression: "ga:newUsers"
47
+ ),
48
+ Google::Apis::AnalyticsreportingV4::Metric.new(
49
+ expression: "ga:pageviewsPerSession"
50
+ ),
51
+ Google::Apis::AnalyticsreportingV4::Metric.new(
52
+ expression: "ga:sessions"
53
+ ),
54
+ Google::Apis::AnalyticsreportingV4::Metric.new(
55
+ expression: "ga:sessionDuration"
56
+ ),
57
+ # Google::Apis::AnalyticsreportingV4::Metric.new(
58
+ # expression: "ga:organicSearches"
59
+ # ),
60
+ Google::Apis::AnalyticsreportingV4::Metric.new(
61
+ expression: "ga:users"
62
+ )
63
+ ],
64
+ metric_filter_clauses: [
65
+ Google::Apis::AnalyticsreportingV4::MetricFilterClause.new(
66
+ filters: [
67
+ Google::Apis::AnalyticsreportingV4::MetricFilter.new(
68
+ metric_name: "ga:pageviews",
69
+ comparison_value: "0",
70
+ operator: "GREATER_THAN"
71
+ )
72
+ ]
73
+ )
74
+ ],
75
+ include_empty_rows: true
76
+ )
77
+
78
+ # puts "request.to_json: #{JSON.pretty_generate(JSON.parse(request.to_json))}" if options[:debug]
79
+ get_reports_requests = Google::Apis::AnalyticsreportingV4::GetReportsRequest.new(report_requests: [request])
80
+ # puts get_reports_requests.to_json if options[:debug]
81
+ puts JSON.pretty_generate(JSON.parse(get_reports_requests.to_json)) if options[:debug]
82
+ return nil if options[:dry_run]
83
+
84
+ result = service.batch_get_reports(get_reports_requests)
85
+ puts "result: #{result.inspect}" if options[:debug]
86
+ result
87
+ end
88
+
89
+ def csv(result)
90
+ result = result.to_json if result.is_a?(Google::Apis::AnalyticsreportingV4::GetReportsResponse)
91
+ result = JSON.parse(result) if result.is_a?(String)
92
+ CSV.generate do |csv|
93
+ result["reports"].each do |report|
94
+ # puts report.column_header.dimensions.inspect
95
+ # puts report.column_header.metric_header.metric_header_entries.map(&:name).inspect
96
+ csv << csv_header_row(report)
97
+ report["data"]["rows"].each do |row|
98
+ csv << csv_data_row(row["dimensions"], row["metrics"])
99
+ end
100
+ csv << csv_data_row("Totals", report["data"]["totals"]) if report["data"]["totals"]
101
+ end
102
+ end
103
+ end
104
+
105
+ def csv_data_row(row_headers, metrics)
106
+ (Array(row_headers) || []) + metrics[0]["values"]
107
+ end
108
+
109
+ def csv_header_row(report)
110
+ (report["columnHeader"]["dimensions"] || []) + report["columnHeader"]["metricHeader"]["metricHeaderEntries"].map do |entry|
111
+ entry["name"]
112
+ end
113
+ end
114
+
115
+ def pp(result)
116
+ JSON.pretty_generate(JSON.parse(result))
117
+ end
118
+ end
119
+
120
+ def initialize(query_string, options)
121
+ # puts "query_string: #{query_string}"
122
+ puts "Initializing query. Options: #{options.inspect}" if options[:debug]
123
+
124
+ puts "options[:access_token]: #{options[:access_token]}"
125
+ @access_token = options[:access_token]
126
+ puts "options[:credentials]: #{options[:credentials]}"
127
+ @access_token ||= access_token_from_credentials(options[:credentials])
128
+ puts "Final access_token: #{access_token}"
129
+ @dry_run = options[:dry_run]
130
+
131
+ query_string = JSON.parse(query_string) unless query_string.is_a?(Hash)
132
+ @query = {}
133
+ @query["reportRequests"] = query_string["reportRequests"].map do |report_request|
134
+ report_request["viewId"] = options[:view_id]
135
+ report_request["dateRanges"] = [
136
+ "startDate": options[:start_date],
137
+ "endDate": options[:end_date]
138
+ ]
139
+ report_request
140
+ end
141
+ # puts "query: #{JSON.pretty_generate(query)}"
142
+ end
143
+
144
+ def execute
145
+ uri = URI.parse("https://analyticsreporting.googleapis.com/v4/reports:batchGet")
146
+ https = Net::HTTP.new(uri.host, uri.port)
147
+ https.use_ssl = true
148
+ # https.set_debug_output($stdout)
149
+ request = Net::HTTP::Post.new(uri.request_uri,
150
+ "Content-Type" => "application/json",
151
+ "Authorization" => "Bearer #{access_token}")
152
+ request.body = query.to_json
153
+ response = https.request(request)
154
+ response
155
+ end
156
+
157
+ private
158
+
159
+ attr_reader :access_token, :dry_run, :query
160
+
161
+ def access_token_from_credentials(credential_file_name)
162
+ stat = File::Stat.new(credential_file_name)
163
+ if stat.world_readable? || stat.world_writable?
164
+ raise "#{credential_file_name} must be readable and writable only by you."
165
+ end
166
+ authorization = Google::Auth::ServiceAccountCredentials.make_creds(
167
+ json_key_io: File.open(credential_file_name),
168
+ scope: "https://www.googleapis.com/auth/analytics.readonly"
169
+ )
170
+ token = authorization.fetch_access_token!
171
+ puts token
172
+ token["access_token"]
173
+ end
174
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gaapi
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0alpha1
5
+ platform: ruby
6
+ authors:
7
+ - Larry Reid
8
+ - Phil Carrillo
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2018-03-23 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: google-api-client
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '0.19'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '0.19'
28
+ description: |2
29
+ Submit queries expressed in JSON to Google Analytics. Can be run
30
+ from unattended scripts, batch jobs, etc.
31
+ email: larry.reid@weenhanceit.com
32
+ executables:
33
+ - gaapi
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - bin/gaapi
38
+ - lib/gaapi.rb
39
+ - lib/gaapi/main.rb
40
+ - lib/gaapi/query.rb
41
+ homepage: https://github.com/weenhanceit/gaapi
42
+ licenses:
43
+ - MIT
44
+ metadata: {}
45
+ post_install_message:
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">"
57
+ - !ruby/object:Gem::Version
58
+ version: 1.3.1
59
+ requirements: []
60
+ rubyforge_project:
61
+ rubygems_version: 2.5.2.1
62
+ signing_key:
63
+ specification_version: 4
64
+ summary: Query Google Analytics from the command line.
65
+ test_files: []