Class: Contacts::Google

Inherits:
Object
  • Object
show all
Defined in:
lib/contacts/google.rb

Overview

Fetching Google Contacts

First, get the user to follow the following URL:

Contacts::Google.authentication_url('http://mysite.com/invite')

After he authenticates successfully to Google, it will redirect him back to the target URL (specified as argument above) and provide the token GET parameter. Use it to create a new instance of this class and request the contact list:

gmail = Contacts::Google.new(params[:token])
gmail.contacts
# => [#<Contact 1>, #<Contact 2>, ...]

Storing a session token

The basic token that you will get after the user has authenticated on Google is valid for only one request. However, you can specify that you want a session token which doesn’t expire:

Contacts::Google.authentication_url('http://mysite.com/invite', :session => true)

When the user authenticates, he will be redirected back with a token that can be exchanged for a session token with the following method:

token = Contacts::Google.sesion_token(params[:token])

Now you have a permanent token. Store it with other user data so you can query the API on his behalf without him having to authenticate on Google each time.

Constant Summary collapse

DOMAIN =
'www.google.com'
AuthSubPath =

all variants go over HTTPS

'/accounts/AuthSub'
ClientLogin =
'/accounts/ClientLogin'
FeedsPath =
'/m8/feeds/contacts/'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(token, user_id = 'default', client = false) ⇒ Google

A token is required here. By default, an AuthSub token from Google is one-time only, which means you can only make a single request with it.



113
114
115
116
117
118
119
120
121
# File 'lib/contacts/google.rb', line 113

def initialize(token, user_id = 'default', client = false)
  @user    = user_id.to_s
  @token   = token.to_s
  @headers = {
    'Accept-Encoding' => 'gzip',
    'User-Agent' => Identifier + ' (gzip)'
  }.update(self.class.authorization_header(@token, client))
  @projection = 'thin'
end

Instance Attribute Details

#headersObject (readonly)

Returns the value of attribute headers.



108
109
110
# File 'lib/contacts/google.rb', line 108

def headers
  @headers
end

#projectionObject

Returns the value of attribute projection.



109
110
111
# File 'lib/contacts/google.rb', line 109

def projection
  @projection
end

#tokenObject (readonly)

Returns the value of attribute token.



108
109
110
# File 'lib/contacts/google.rb', line 108

def token
  @token
end

#userObject (readonly)

Returns the value of attribute user.



108
109
110
# File 'lib/contacts/google.rb', line 108

def user
  @user
end

Class Method Details

.authentication_url(target, options = {}) ⇒ Object

URL to Google site where user authenticates. Afterwards, Google redirects to your site with the URL specified as target.

Options are:

  • :scope – the AuthSub scope in which the resulting token is valid (default: “www.google.com/m8/feeds/contacts/”)

  • :secure – boolean indicating whether the token will be secure. Only available for registered domains. (default: false)

  • :session – boolean indicating if the token can be exchanged for a session token (default: false)



75
76
77
78
79
80
# File 'lib/contacts/google.rb', line 75

def self.authentication_url(target, options = {})
  params = authentication_url_options.merge(options)
  params[:next] = target
  query = query_string(params)
  "https://#{DOMAIN}#{AuthSubPath}Request?#{query}"
end

.authentication_url_optionsObject

default options for #authentication_url



47
48
49
50
51
52
53
# File 'lib/contacts/google.rb', line 47

def self.authentication_url_options
  @authentication_url_options ||= {
    :scope => "http://#{DOMAIN}#{FeedsPath}",
    :secure => false,
    :session => false
  }
end

.client_login(email, password) ⇒ Object

Alternative to AuthSub: using email and password.



97
98
99
100
101
102
103
104
105
106
# File 'lib/contacts/google.rb', line 97

def self.(email, password)
  response = http_start do |google|
    query = query_string(.merge(:Email => email, :Passwd => password))
    puts "posting #{query} to #{ClientLogin}" if Contacts::verbose?
    google.post(ClientLogin, query)
  end

  pair = response.body.split(/\n/).detect { |p| p.index('Auth=') == 0 }
  pair.split('=').last if pair
end

.client_login_optionsObject

default options for #client_login



56
57
58
59
60
61
62
# File 'lib/contacts/google.rb', line 56

def self.
  @client_login_options ||= {
    :accountType => 'GOOGLE',
    :service => 'cp',
    :source => 'Contacts-Ruby'
  }
end

.session_token(token) ⇒ Object

Makes an HTTPS request to exchange the given token with a session one. Session tokens never expire, so you can store them in the database alongside user info.

Returns the new token as string or nil if the parameter couldn’t be found in response body.



87
88
89
90
91
92
93
94
# File 'lib/contacts/google.rb', line 87

def self.session_token(token)
  response = http_start do |google|
    google.get(AuthSubPath + 'SessionToken', authorization_header(token))
  end

  pair = response.body.split(/\n/).detect { |p| p.index('Token=') == 0 }
  pair.split('=').last if pair
end

Instance Method Details

#all_contacts(options = {}, chunk_size = 200) ⇒ Object

Fetches contacts using multiple API calls when necessary



159
160
161
# File 'lib/contacts/google.rb', line 159

def all_contacts(options = {}, chunk_size = 200)
  in_chunks(options, :contacts, chunk_size)
end

#contacts(options = {}) ⇒ Object

Fetches, parses and returns the contact list.

Options

  • :limit – use a large number to fetch a bigger contact list (default: 200)

  • :offset – 0-based value, can be used for pagination

  • :order – currently the only value support by Google is “lastmodified”

  • :descending – boolean

  • :updated_after – string or time-like object, use to only fetch contacts that were updated after this date



152
153
154
155
156
# File 'lib/contacts/google.rb', line 152

def contacts(options = {})
  params = { :limit => 200 }.update(options)
  response = get(params)
  parse_contacts response_body(response)
end

#get(params) ⇒ Object

:nodoc:



123
124
125
126
127
128
129
130
# File 'lib/contacts/google.rb', line 123

def get(params) # :nodoc:
  self.class.http_start(false) do |google|
    path = FeedsPath + CGI.escape(@user)
    google_params = translate_parameters(params)
    query = self.class.query_string(google_params)
    google.get("#{path}/#{@projection}?#{query}", @headers)
  end
end

#updated_atObject

Timestamp of last update. This value is available only after the XML document has been parsed; for instance after fetching the contact list.



134
135
136
# File 'lib/contacts/google.rb', line 134

def updated_at
  @updated_at ||= Time.parse @updated_string if @updated_string
end

#updated_at_stringObject

Timestamp of last update as it appeared in the XML document



139
140
141
# File 'lib/contacts/google.rb', line 139

def updated_at_string
  @updated_string
end