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])
contacts = gmail.contacts
#-> [ ['Fitzgerald', '[email protected]', '[email protected]'],
      ['William Paginate', '[email protected]'], ...
      ]

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.



117
118
119
120
121
122
123
124
125
# File 'lib/contacts/google.rb', line 117

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.



112
113
114
# File 'lib/contacts/google.rb', line 112

def headers
  @headers
end

#projectionObject

Returns the value of attribute projection.



113
114
115
# File 'lib/contacts/google.rb', line 113

def projection
  @projection
end

#tokenObject (readonly)

Returns the value of attribute token.



112
113
114
# File 'lib/contacts/google.rb', line 112

def token
  @token
end

#userObject (readonly)

Returns the value of attribute user.



112
113
114
# File 'lib/contacts/google.rb', line 112

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)



79
80
81
82
83
84
# File 'lib/contacts/google.rb', line 79

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



51
52
53
54
55
56
57
# File 'lib/contacts/google.rb', line 51

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.



101
102
103
104
105
106
107
108
109
110
# File 'lib/contacts/google.rb', line 101

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



60
61
62
63
64
65
66
# File 'lib/contacts/google.rb', line 60

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.



91
92
93
94
95
96
97
98
# File 'lib/contacts/google.rb', line 91

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



163
164
165
# File 'lib/contacts/google.rb', line 163

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



156
157
158
159
160
# File 'lib/contacts/google.rb', line 156

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

#get(params) ⇒ Object

:nodoc:



127
128
129
130
131
132
133
134
# File 'lib/contacts/google.rb', line 127

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.



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

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



143
144
145
# File 'lib/contacts/google.rb', line 143

def updated_at_string
  @updated_string
end