Navigation Menu

Skip to content

Commit

Permalink
merget chrisle gattica
Browse files Browse the repository at this point in the history
  • Loading branch information
vgololobov committed Mar 20, 2012
2 parents 0826d69 + a3a4a98 commit fbcdaeb
Show file tree
Hide file tree
Showing 12 changed files with 209 additions and 97 deletions.
3 changes: 3 additions & 0 deletions Gemfile
@@ -1,3 +1,6 @@
source "http://rubygems.org"
gemspec
gem 'test-unit'
gem 'hpricot' #, 0.8.6
gem 'test-unit' #, 2.4.5
gem 'bundler' #, 1.0.21
12 changes: 12 additions & 0 deletions Gemfile.lock
@@ -1,20 +1,32 @@
PATH
remote: .
specs:
<<<<<<< HEAD
gattica (0.5.1)
=======
gattica (0.6.0)
gattica
>>>>>>> upstream/master
hpricot
test-unit

GEM
remote: http://rubygems.org/
specs:
hpricot (0.8.6)
<<<<<<< HEAD
rake (0.9.2.2)
=======
>>>>>>> upstream/master
test-unit (2.4.5)

PLATFORMS
ruby

DEPENDENCIES
<<<<<<< HEAD
rake
=======
gattica!
>>>>>>> upstream/master
test-unit
41 changes: 32 additions & 9 deletions README.md
@@ -1,11 +1,3 @@
This Fork
=======
Deviantech's fork of the Gattica gem has the following modifications:

* Authentication by token actually works

-------

Gattica
=======
Gattica is an easy to use Gem for getting data from the Google Analytics API.
Expand Down Expand Up @@ -422,6 +414,37 @@ History

Version history
---------------
### 0.6.1
* Incorporated fixes by vgololobov
* Removed circular dependency
* Fixed 1.9.3 init exception https://github.com/chrisle/gattica/pull/6

### 0.6.0
* Update to use Google Analytics v2.4 management API

TL;DR: Uses the v2.4 API now because Google deprecated <2.3.

* :) - Drop-in replacement for you.
* :) - Won't timeout anymore.
* :) - Accounts method might be faster if you have a few profiles
* :( - Accounts method is notably slower if you have >1000 profiles.

Google has changed the output of the API < 2.3. Most notable changes
were the output of what was the /management/accounts/default call. Some
of the XML changed, but most notably it didn't return everything all at
once. It used to look like this: http://bit.ly/w6Ummj

* Fixed token [deviantech]

### 0.5.1
* Added some tests - needs more work :(

### 0.4.7
* Removed version numbers [john mcgrath]

### 0.4.6
* Removed monkey patch [mathieuravaux]

### 0.4.4
* Added a configuration file to unit tests
* Removed version.rb. Not needed. (thanks John McGrath see: github.com/john)
Expand Down Expand Up @@ -480,4 +503,4 @@ Maintainer history
* [Rob Cameron](https://github.com/activenetwork/gattica) (2010)
* [Mike Rumble](https://github.com/rumble/gattica) (2010)
* [Chris Le](https://github.com/chrisle/gattica) (Current)


6 changes: 3 additions & 3 deletions VERSION.yml
@@ -1,5 +1,5 @@
---
---
:major: 0
:minor: 5
:minor: 6
:patch: 1
:build:
:build: !!null
26 changes: 13 additions & 13 deletions gattica.gemspec
Expand Up @@ -4,20 +4,21 @@
# -*- encoding: utf-8 -*-

Gem::Specification.new do |s|
s.name = %q{gattica}
s.version = "0.5.1"
s.name = "gattica"
s.version = "0.6.1"

s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = [%q{Christopher Le, et all}]
s.date = %q{2011-06-06}
s.description = %q{Gattica is a easy to use Ruby Gem for getting data from the Google Analytics API. It supports metrics, dimensions, sort, filters, goals, and segments. It can handle accounts with 1000+ profiles, and can return data in CSV, Hash, or JSON}
s.email = %q{chrisl@seerinteractive.com}
s.authors = ["Christopher Le, et all"]
s.date = "2012-01-31"
s.description = "Gattica is a easy to use Ruby Gem for getting data from the Google Analytics API. It supports metrics, dimensions, sort, filters, goals, and segments. It can handle accounts with 1000+ profiles, and can return data in CSV, Hash, or JSON"
s.email = "chrisl@seerinteractive.com"
s.extra_rdoc_files = [
"LICENSE",
"README.md"
]
s.files = [
"Gemfile",
"Gemfile.lock",
"LICENSE",
"README.md",
"Rakefile",
Expand All @@ -31,7 +32,9 @@ Gem::Specification.new do |s|
"lib/gattica/data_set.rb",
"lib/gattica/engine.rb",
"lib/gattica/exceptions.rb",
"lib/gattica/goals.rb",
"lib/gattica/hash_extensions.rb",
"lib/gattica/profiles.rb",
"lib/gattica/segment.rb",
"lib/gattica/settings.rb",
"lib/gattica/user.rb",
Expand All @@ -42,26 +45,23 @@ Gem::Specification.new do |s|
"test/test_results.rb",
"test/test_user.rb"
]
s.homepage = %q{http://github.com/chrisle/gattica}
s.require_paths = [%q{lib}]
s.rubygems_version = %q{1.8.4}
s.summary = %q{Gattica is a easy to use Ruby Gem for getting data from the Google Analytics API.}
s.homepage = "http://github.com/chrisle/gattica"
s.require_paths = ["lib"]
s.rubygems_version = "1.8.10"
s.summary = "Gattica is a easy to use Ruby Gem for getting data from the Google Analytics API."

if s.respond_to? :specification_version then
s.specification_version = 3

if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q<test-unit>, [">= 0"])
s.add_development_dependency(%q<rake>, [">= 0"])
s.add_runtime_dependency(%q<hpricot>, [">= 0"])
else
s.add_dependency(%q<test-unit>, [">= 0"])
s.add_dependency(%q<rake>, [">= 0"])
s.add_dependency(%q<hpricot>, [">= 0"])
end
else
s.add_dependency(%q<test-unit>, [">= 0"])
s.add_dependency(%q<rake>, [">= 0"])
s.add_dependency(%q<hpricot>, [">= 0"])
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/gattica.rb
Expand Up @@ -25,7 +25,7 @@
# Please see the README for usage docs.
module Gattica

VERSION = '0.5.1'
VERSION = '0.6.1'

# Creates a new instance of Gattica::Engine
def self.new(*args)
Expand Down
62 changes: 41 additions & 21 deletions lib/gattica/account.rb
@@ -1,34 +1,54 @@
require 'rubygems'
require 'hpricot'

module Gattica

# Represents an account that an authenticated user has access to

class Account

include Convertible

attr_reader :id, :updated, :title, :table_id, :account_id, :account_name,
:profile_id, :web_property_id, :goals

def initialize(xml)
@id = xml.at(:id).inner_html
@id = xml.at("link[@rel='self']").attributes['href']
@updated = DateTime.parse(xml.at(:updated).inner_html)
@title = xml.at(:title).inner_html
@table_id = xml.at('dxp:tableid').inner_html
@account_id = xml.at("dxp:property[@name='ga:accountId']").attributes['value'].to_i
@account_name = xml.at("dxp:property[@name='ga:accountName']").attributes['value']
@profile_id = xml.at("dxp:property[@name='ga:profileId']").attributes['value'].to_i
@web_property_id = xml.at("dxp:property[@name='ga:webPropertyId']").attributes['value']
@goals = xml.search('ga:goal').collect do |goal| {
:active => goal.attributes['active'],
:name => goal.attributes['name'],
:number => goal.attributes['number'].to_i,
:value => goal.attributes['value'].to_f,
}
@account_id = find_account_id(xml)

@title = xpath_value(xml, "dxp:property[@name='ga:profileName']")
@table_id = xpath_value(xml, "dxp:property[@name='dxp:tableId']")
@profile_id = find_profile_id(xml)
@web_property_id = xpath_value(xml, "dxp:property[@name='ga:webPropertyId']")
@goals = []
end

def xpath_value(xml, xpath)
xml.at(xpath).attributes['value']
end

def find_account_id(xml)
xml.at("dxp:property[@name='ga:accountId']").attributes['value'].to_i
end

def find_account_name(xml)
xml.at("dxp:property[@name='ga:accountName']").attributes['value']
end

def find_profile_id(xml)
xml.at("dxp:property[@name='ga:profileId']").attributes['value'].to_i
end

def set_account_name(account_feed_entry)
if @account_id == find_account_id(account_feed_entry)
@account_name = find_account_name(account_feed_entry)
end
end


def set_goals(goals_feed_entry)
if @profile_id == find_profile_id(goals_feed_entry)
goal = goals_feed_entry.search('ga:goal').first
@goals.push({
:active => goal.attributes['active'],
:name => goal.attributes['name'],
:number => goal.attributes['number'].to_i,
:value => goal.attributes['value'].to_f
})
end
end
end
end
7 changes: 0 additions & 7 deletions lib/gattica/auth.rb
@@ -1,12 +1,5 @@
require 'net/http'
require 'net/https'

module Gattica

# Authenticates a user against the Google Client Login system

class Auth

include Convertible

SCRIPT_NAME = '/accounts/ClientLogin'
Expand Down
60 changes: 36 additions & 24 deletions lib/gattica/engine.rb
Expand Up @@ -2,7 +2,7 @@ module Gattica
class Engine

attr_reader :user
attr_accessor :profile_id, :token
attr_accessor :profile_id, :token, :user_accounts

# Initialize Gattica using username/password or token.
#
Expand All @@ -19,9 +19,8 @@ class Engine
def initialize(options={})
@options = Settings::DEFAULT_OPTIONS.merge(options)
handle_init_options(@options)
create_http_connection()
create_http_connection('www.google.com')
check_init_auth_requirements()
# TODO: check that the user has access to the specified profile and show an error here rather than wait for Google to respond with a message
end

# Returns the list of accounts the user has access to. A user may have
Expand All @@ -43,13 +42,32 @@ def initialize(options={})
# See Gattica::Engine#get to see how to get some data.

def accounts
# if we haven't retrieved the user's accounts yet, get them now and save them
if @user_accounts.nil?
data = request_default_account_feed
xml = Hpricot(data)
@user_accounts = xml.search(:entry).collect { |entry| Account.new(entry) }
create_http_connection('www.googleapis.com')

# get profiles
response = do_http_get("/analytics/v2.4/management/accounts/~all/webproperties/~all/profiles?max-results=10000")
xml = Hpricot(response)
@user_accounts = xml.search(:entry).collect { |profile_xml|
Account.new(profile_xml)
}

# Fill in the goals
response = do_http_get("/analytics/v2.4/management/accounts/~all/webproperties/~all/profiles/~all/goals?max-results=10000")
xml = Hpricot(response)
@user_accounts.each do |ua|
xml.search(:entry).each { |e| ua.set_goals(e) }
end

# Fill in the account name
response = do_http_get("/analytics/v2.4/management/accounts?max-results=10000")
xml = Hpricot(response)
@user_accounts.each do |ua|
xml.search(:entry).each { |e| ua.set_account_name(e) }
end

end
return @user_accounts
@user_accounts
end

# Returns the list of segments available to the authenticated user.
Expand All @@ -68,9 +86,11 @@ def accounts

def segments
if @user_segments.nil?
data = request_default_account_feed
xml = Hpricot(data)
@user_segments = xml.search("dxp:segment").collect { |s| Segment.new(s) }
response = do_http_get("/analytics/v2.4/management/segments?max-results=10000")
xml = Hpricot(response)
@user_segments = xml.search("dxp:segment").collect { |s|
Segment.new(s)
}
end
return @user_segments
end
Expand Down Expand Up @@ -114,8 +134,8 @@ def get(args={})
args = validate_and_clean(Settings::DEFAULT_ARGS.merge(args))
query_string = build_query_string(args,@profile_id)
@logger.debug(query_string) if @debug
data = do_http_get("/analytics/feeds/data?#{query_string}")
#data = do_http_get("/analytics/feeds/data?ids=ga%3A915568&metrics=ga%3Avisits&segment=gaid%3A%3A-7&start-date=2010-03-29&end-date=2010-03-29&max-results=50")
create_http_connection('www.googleapis.com')
data = do_http_get("/analytics/v2.4/data?#{query_string}")
return DataSet.new(Hpricot.XML(data))
end

Expand All @@ -132,14 +152,6 @@ def token=(token)
######################################################################
private

# Gets the default account feed from Google
def request_default_account_feed
if @default_account_feed.nil?
@default_account_feed = do_http_get('/analytics/feeds/accounts/default')
end
return @default_account_feed
end

# Does the work of making HTTP calls and then going through a suite of tests on the response to make
# sure it's valid and not an error

Expand Down Expand Up @@ -246,9 +258,9 @@ def validate_and_clean(args)
return args
end

def create_http_connection
def create_http_connection(server)
port = Settings::USE_SSL ? Settings::SSL_PORT : Settings::NON_SSL_PORT
@http = Net::HTTP.new(Settings::SERVER, port)
@http = Net::HTTP.new(server, port)
@http.use_ssl = Settings::USE_SSL
@http.set_debug_output $stdout if @options[:debug]
@http.read_timeout = @options[:timeout] if @options[:timeout]
Expand All @@ -268,7 +280,7 @@ def handle_init_options(options)
# If the authorization is a email and password then create User objects
# or if it's a previous token, use that. Else, raise exception.
def check_init_auth_requirements
if @options[:token].to_s.length > 200 # Not sure actual required length, but mine's 267
if @options[:token].to_s.length > 200
self.token = @options[:token]
elsif @options[:email] && @options[:password]
@user = User.new(@options[:email], @options[:password])
Expand Down

0 comments on commit fbcdaeb

Please sign in to comment.