Class: GoogleDrive::Session
- Inherits:
-
Object
- Object
- GoogleDrive::Session
- Extended by:
- Util
- Includes:
- Util
- Defined in:
- lib/google_drive/session.rb
Overview
Use GoogleDrive.login or GoogleDrive.saved_session to get GoogleDrive::Session object.
Constant Summary collapse
- UPLOAD_CHUNK_SIZE =
512 * 1024
Constants included from Util
Util::DOCS_BASE_URL, Util::EXT_TO_CONTENT_TYPE
Instance Attribute Summary collapse
-
#on_auth_fail ⇒ Object
Proc or Method called when authentication has failed.
Class Method Summary collapse
-
.login(mail, password, proxy = nil) ⇒ Object
The same as GoogleDrive.login.
-
.login_with_oauth(access_token, proxy = nil) ⇒ Object
The same as GoogleDrive.login_with_oauth.
-
.new_dummy ⇒ Object
Creates a dummy GoogleDrive::Session object for testing.
-
.restore_session(auth_tokens, proxy = nil) ⇒ Object
The same as GoogleDrive.restore_session.
Instance Method Summary collapse
-
#auth_token(auth = :wise) ⇒ Object
Authentication token.
-
#auth_tokens ⇒ Object
Authentication tokens.
-
#collection_by_title(title) ⇒ Object
Returns a top-level collection whose title exactly matches
title
as GoogleDrive::Collection. -
#collection_by_url(url) ⇒ Object
Returns GoogleDrive::Collection with given
url
. -
#collections ⇒ Object
Returns the top-level collections (direct children of the root collection).
-
#create_spreadsheet(title = "Untitled", feed_url = "https://docs.google.com/feeds/documents/private/full") ⇒ Object
Creates new spreadsheet and returns the new GoogleDrive::Spreadsheet.
-
#entry_element_to_file(entry) ⇒ Object
:nodoc:.
-
#file_by_title(title) ⇒ Object
Returns GoogleDrive::File or its subclass whose title exactly matches
title
. -
#files(params = {}) ⇒ Object
Returns list of files for the user as array of GoogleDrive::File or its subclass.
-
#initialize(auth_tokens = nil, fetcher = nil, proxy = nil) ⇒ Session
constructor
DEPRECATED: Use GoogleDrive.restore_session instead.
- #inspect ⇒ Object
-
#login(mail, password) ⇒ Object
Authenticates with given
mail
andpassword
, and updates current session object if succeeds. -
#request(method, url, params = {}) ⇒ Object
:nodoc:.
-
#root_collection ⇒ Object
Returns the root collection.
-
#spreadsheet_by_key(key) ⇒ Object
Returns GoogleDrive::Spreadsheet with given
key
. -
#spreadsheet_by_title(title) ⇒ Object
Returns GoogleDrive::Spreadsheet with given
title
. -
#spreadsheet_by_url(url) ⇒ Object
Returns GoogleDrive::Spreadsheet with given
url
. -
#spreadsheets(params = {}) ⇒ Object
Returns list of spreadsheets for the user as array of GoogleDrive::Spreadsheet.
-
#upload_from_file(path, title = nil, params = {}) ⇒ Object
Uploads a local file.
-
#upload_from_io(io, title = "Untitled", params = {}) ⇒ Object
Uploads a file.
-
#upload_from_string(content, title = "Untitled", params = {}) ⇒ Object
Uploads a file with the given
title
andcontent
. -
#upload_raw(method, url, io, title = "Untitled", params = {}) ⇒ Object
:nodoc:.
-
#worksheet_by_url(url) ⇒ Object
Returns GoogleDrive::Worksheet with given
url
.
Methods included from Util
concat_url, encode_query, h, to_v3_url
Constructor Details
#initialize(auth_tokens = nil, fetcher = nil, proxy = nil) ⇒ Session
DEPRECATED: Use GoogleDrive.restore_session instead.
70 71 72 73 74 75 76 |
# File 'lib/google_drive/session.rb', line 70 def initialize(auth_tokens = nil, fetcher = nil, proxy = nil) if fetcher @fetcher = fetcher else @fetcher = ClientLoginFetcher.new(auth_tokens || {}, proxy) end end |
Instance Attribute Details
#on_auth_fail ⇒ Object
Proc or Method called when authentication has failed. When this function returns true
, it tries again.
114 115 116 |
# File 'lib/google_drive/session.rb', line 114 def on_auth_fail @on_auth_fail end |
Class Method Details
.login(mail, password, proxy = nil) ⇒ Object
The same as GoogleDrive.login.
36 37 38 39 40 |
# File 'lib/google_drive/session.rb', line 36 def self.login(mail, password, proxy = nil) session = Session.new(nil, ClientLoginFetcher.new({}, proxy)) session.login(mail, password) return session end |
.login_with_oauth(access_token, proxy = nil) ⇒ Object
The same as GoogleDrive.login_with_oauth.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/google_drive/session.rb', line 43 def self.login_with_oauth(access_token, proxy = nil) case access_token when OAuth::AccessToken raise(GoogleDrive::Error, "proxy is not supported with OAuth1.") if proxy fetcher = OAuth1Fetcher.new(access_token) when OAuth2::AccessToken fetcher = OAuth2Fetcher.new(access_token.token, proxy) when String fetcher = OAuth2Fetcher.new(access_token, proxy) else raise(GoogleDrive::Error, "access_token is neither String, OAuth2::Token nor OAuth::Token: %p" % access_token) end return Session.new(nil, fetcher) end |
Instance Method Details
#auth_token(auth = :wise) ⇒ Object
Authentication token.
108 109 110 |
# File 'lib/google_drive/session.rb', line 108 def auth_token(auth = :wise) return self.auth_tokens[auth] end |
#auth_tokens ⇒ Object
Authentication tokens.
98 99 100 101 102 103 104 105 |
# File 'lib/google_drive/session.rb', line 98 def auth_tokens if !@fetcher.is_a?(ClientLoginFetcher) raise(GoogleDrive::Error, "Cannot call auth_tokens for session created by " + "login_with_oauth.") end return @fetcher.auth_tokens end |
#collection_by_title(title) ⇒ Object
Returns a top-level collection whose title exactly matches title
as GoogleDrive::Collection. Returns nil if not found. If multiple collections with the title
are found, returns one of them.
233 234 235 |
# File 'lib/google_drive/session.rb', line 233 def collection_by_title(title) return self.root_collection.subcollection_by_title(title) end |
#collection_by_url(url) ⇒ Object
Returns GoogleDrive::Collection with given url
. You must specify either of:
-
URL of the page you get when you go to docs.google.com/ with your browser and open a collection
-
URL of collection (folder) feed
e.g.
session.collection_by_url(
"https://drive.google.com/#folders/" +
"0B9GfDpQ2pBVUODNmOGE0NjIzMWU3ZC00NmUyLTk5NzEtYaFkZjY1MjAyxjMc")
session.collection_by_url(
"http://docs.google.com/feeds/default/private/full/folder%3A" +
"0B9GfDpQ2pBVUODNmOGE0NjIzMWU3ZC00NmUyLTk5NzEtYaFkZjY1MjAyxjMc")
250 251 252 253 254 255 256 257 258 |
# File 'lib/google_drive/session.rb', line 250 def collection_by_url(url) uri = URI.parse(url) if ["docs.google.com", "drive.google.com"].include?(uri.host) && uri.fragment =~ /^folders\/(.+)$/ # Looks like a URL of human-readable collection page. Converts to collection feed URL. url = "#{DOCS_BASE_URL}/folder%3A#{$1}" end return Collection.new(self, to_v3_url(url)) end |
#collections ⇒ Object
Returns the top-level collections (direct children of the root collection).
225 226 227 |
# File 'lib/google_drive/session.rb', line 225 def collections return self.root_collection.subcollections end |
#create_spreadsheet(title = "Untitled", feed_url = "https://docs.google.com/feeds/documents/private/full") ⇒ Object
Creates new spreadsheet and returns the new GoogleDrive::Spreadsheet.
e.g.
session.create_spreadsheet("My new sheet")
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'lib/google_drive/session.rb', line 264 def create_spreadsheet( title = "Untitled", feed_url = "https://docs.google.com/feeds/documents/private/full") xml = <<-"EOS" <atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007"> <atom:category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#spreadsheet" label="spreadsheet"/> <atom:title>#{h(title)}</atom:title> </atom:entry> EOS doc = request(:post, feed_url, :data => xml, :auth => :writely) ss_url = doc.css( "link[rel='http://schemas.google.com/spreadsheets/2006#worksheetsfeed']")[0]["href"] return Spreadsheet.new(self, ss_url, title) end |
#entry_element_to_file(entry) ⇒ Object
:nodoc:
406 407 408 409 410 411 412 413 414 415 416 417 418 419 |
# File 'lib/google_drive/session.rb', line 406 def entry_element_to_file(entry) #:nodoc: type, resource_id = entry.css("gd|resourceId").text.split(/:/) title = entry.css("title").text case type when "folder" return Collection.new(self, entry) when "spreadsheet" worksheets_feed_link = entry.css( "link[rel='http://schemas.google.com/spreadsheets/2006#worksheetsfeed']")[0] return Spreadsheet.new(self, worksheets_feed_link["href"], title) else return GoogleDrive::File.new(self, entry) end end |
#file_by_title(title) ⇒ Object
Returns GoogleDrive::File or its subclass whose title exactly matches title
. Returns nil if not found. If multiple files with the title
are found, returns one of them.
If given an Array, traverses collections by title. e.g.
session.file_by_title(["myfolder", "mysubfolder/even/w/slash", "myfile"])
138 139 140 141 142 143 144 |
# File 'lib/google_drive/session.rb', line 138 def file_by_title(title) if title.is_a?(Array) return self.root_collection.file_by_title(title) else return files("title" => title, "title-exact" => "true")[0] end end |
#files(params = {}) ⇒ Object
Returns list of files for the user as array of GoogleDrive::File or its subclass. You can specify query parameters described at developers.google.com/google-apps/documents-list/#getting_a_list_of_documents_and_files
files doesn’t return collections unless “showfolders” => true is specified.
e.g.
session.files
session.files("title" => "hoge", "title-exact" => "true")
125 126 127 128 129 130 |
# File 'lib/google_drive/session.rb', line 125 def files(params = {}) url = concat_url( "#{DOCS_BASE_URL}?v=3", "?" + encode_query(params)) doc = request(:get, url, :auth => :writely) return doc.css("feed > entry").map(){ |e| entry_element_to_file(e) } end |
#inspect ⇒ Object
452 453 454 |
# File 'lib/google_drive/session.rb', line 452 def inspect return "#<%p:0x%x>" % [self.class, self.object_id] end |
#login(mail, password) ⇒ Object
Authenticates with given mail
and password
, and updates current session object if succeeds. Raises GoogleDrive::AuthenticationError if fails. Google Apps account is supported.
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/google_drive/session.rb', line 81 def login(mail, password) if !@fetcher.is_a?(ClientLoginFetcher) raise(GoogleDrive::Error, "Cannot call login for session created by login_with_oauth.") end begin @fetcher.auth_tokens = { :wise => authenticate(mail, password, :wise), :writely => authenticate(mail, password, :writely), } rescue GoogleDrive::Error => ex return true if @on_auth_fail && @on_auth_fail.call() raise(AuthenticationError, "Authentication failed for #{mail}: #{ex.}") end end |
#request(method, url, params = {}) ⇒ Object
:nodoc:
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 |
# File 'lib/google_drive/session.rb', line 421 def request(method, url, params = {}) #:nodoc: # Always uses HTTPS. url = url.gsub(%r{^http://}, "https://") data = params[:data] auth = params[:auth] || :wise if params[:header] extra_header = params[:header] elsif data extra_header = {"Content-Type" => "application/atom+xml;charset=utf-8"} else extra_header = {} end response_type = params[:response_type] || :xml while true response = @fetcher.request_raw(method, url, data, extra_header, auth) if response.code == "401" && @on_auth_fail && @on_auth_fail.call() next end if !(response.code =~ /^[23]/) raise( response.code == "401" ? AuthenticationError : GoogleDrive::Error, "Response code #{response.code} for #{method} #{url}: " + CGI.unescapeHTML(response.body)) end return convert_response(response, response_type) end end |
#root_collection ⇒ Object
Returns the root collection.
220 221 222 |
# File 'lib/google_drive/session.rb', line 220 def root_collection return Collection.new(self, Collection::ROOT_URL) end |
#spreadsheet_by_key(key) ⇒ Object
Returns GoogleDrive::Spreadsheet with given key
.
e.g.
# http://spreadsheets.google.com/ccc?key=pz7XtlQC-PYx-jrVMJErTcg&hl=ja
session.spreadsheet_by_key("pz7XtlQC-PYx-jrVMJErTcg")
169 170 171 172 |
# File 'lib/google_drive/session.rb', line 169 def spreadsheet_by_key(key) url = "https://spreadsheets.google.com/feeds/worksheets/#{key}/private/full" return Spreadsheet.new(self, url) end |
#spreadsheet_by_title(title) ⇒ Object
Returns GoogleDrive::Spreadsheet with given title
. Returns nil if not found. If multiple spreadsheets with the title
are found, returns one of them.
204 205 206 |
# File 'lib/google_drive/session.rb', line 204 def spreadsheet_by_title(title) return spreadsheets({"title" => title, "title-exact" => "true"})[0] end |
#spreadsheet_by_url(url) ⇒ Object
Returns GoogleDrive::Spreadsheet with given url
. You must specify either of:
-
URL of the page you open to access the spreadsheet in your browser
-
URL of worksheet-based feed of the spreadseet
e.g.
session.spreadsheet_by_url(
"https://docs.google.com/spreadsheet/ccc?key=pz7XtlQC-PYx-jrVMJErTcg")
session.spreadsheet_by_url(
"https://spreadsheets.google.com/feeds/" +
"worksheets/pz7XtlQC-PYx-jrVMJErTcg/private/full")
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/google_drive/session.rb', line 184 def spreadsheet_by_url(url) # Tries to parse it as URL of human-readable spreadsheet. uri = URI.parse(url) if ["spreadsheets.google.com", "docs.google.com"].include?(uri.host) case uri.path when /\/d\/([^\/]+)/ return spreadsheet_by_key($1) when /\/ccc$/ if (uri.query || "").split(/&/).find(){ |s| s=~ /^key=(.*)$/ } return spreadsheet_by_key($1) end end end # Assumes the URL is worksheets feed URL. return Spreadsheet.new(self, url) end |
#spreadsheets(params = {}) ⇒ Object
Returns list of spreadsheets for the user as array of GoogleDrive::Spreadsheet. You can specify query parameters e.g. “title”, “title-exact”.
e.g.
session.spreadsheets
session.spreadsheets("title" => "hoge")
session.spreadsheets("title" => "hoge", "title-exact" => "true")
153 154 155 156 157 158 159 160 161 162 |
# File 'lib/google_drive/session.rb', line 153 def spreadsheets(params = {}) url = concat_url( "#{DOCS_BASE_URL}/-/spreadsheet?v=3", "?" + encode_query(params)) doc = request(:get, url, :auth => :writely) # The API may return non-spreadsheets too when title-exact is specified. # Probably a bug. For workaround, only returns Spreadsheet instances. return doc.css("feed > entry"). map(){ |e| entry_element_to_file(e) }. select(){ |f| f.is_a?(Spreadsheet) } end |
#upload_from_file(path, title = nil, params = {}) ⇒ Object
Uploads a local file. Returns a GoogleSpreadsheet::File object.
e.g.
# Uploads a text file and converts to a Google Docs document:
session.upload_from_file("/path/to/hoge.txt")
# Uploads without conversion:
session.upload_from_file("/path/to/hoge.txt", "Hoge", :convert => false)
# Uploads with explicit content type:
session.upload_from_file("/path/to/hoge", "Hoge", :content_type => "text/plain")
# Uploads a text file and converts to a Google Spreadsheet:
session.upload_from_file("/path/to/hoge.tsv", "Hoge")
session.upload_from_file("/path/to/hoge.csv", "Hoge")
session.upload_from_file("/path/to/hoge", "Hoge", :content_type => "text/tab-separated-values")
session.upload_from_file("/path/to/hoge", "Hoge", :content_type => "text/csv")
324 325 326 327 328 329 330 |
# File 'lib/google_drive/session.rb', line 324 def upload_from_file(path, title = nil, params = {}) file_name = ::File.basename(path) params = {:file_name => file_name}.merge(params) open(path, "rb") do |f| return upload_from_io(f, title || file_name, params) end end |
#upload_from_io(io, title = "Untitled", params = {}) ⇒ Object
Uploads a file. Reads content from io
. Returns a GoogleSpreadsheet::File object.
334 335 336 337 338 339 340 341 |
# File 'lib/google_drive/session.rb', line 334 def upload_from_io(io, title = "Untitled", params = {}) doc = request(:get, "#{DOCS_BASE_URL}?v=3", :auth => :writely) initial_url = doc.css( "link[rel='http://schemas.google.com/g/2005#resumable-create-media']")[0]["href"] entry = upload_raw(:post, initial_url, io, title, params) return entry_element_to_file(entry) end |
#upload_from_string(content, title = "Untitled", params = {}) ⇒ Object
Uploads a file with the given title
and content
. Returns a GoogleSpreadsheet::File object.
e.g.
# Uploads and converts to a Google Docs document:
session.upload_from_string(
"Hello world.", "Hello", :content_type => "text/plain")
# Uploads without conversion:
session.upload_from_string(
"Hello world.", "Hello", :content_type => "text/plain", :convert => false)
# Uploads and converts to a Google Spreadsheet:
session.upload_from_string("hoge\tfoo\n", "Hoge", :content_type => "text/tab-separated-values")
session.upload_from_string("hoge,foo\n", "Hoge", :content_type => "text/tsv")
302 303 304 |
# File 'lib/google_drive/session.rb', line 302 def upload_from_string(content, title = "Untitled", params = {}) return upload_from_io(StringIO.new(content), title, params) end |
#upload_raw(method, url, io, title = "Untitled", params = {}) ⇒ Object
:nodoc:
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 |
# File 'lib/google_drive/session.rb', line 343 def upload_raw(method, url, io, title = "Untitled", params = {}) #:nodoc: params = {:convert => true}.merge(params) pos = io.pos io.seek(0, IO::SEEK_END) total_bytes = io.pos - pos io.pos = pos content_type = params[:content_type] if !content_type && params[:file_name] content_type = EXT_TO_CONTENT_TYPE[::File.extname(params[:file_name]).downcase] end if !content_type content_type = "application/octet-stream" end initial_xml = <<-"EOS" <entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007"> <title>#{h(title)}</title> </entry> EOS default_initial_header = { "Content-Type" => "application/atom+xml;charset=utf-8", "X-Upload-Content-Type" => content_type, "X-Upload-Content-Length" => total_bytes.to_s(), } initial_full_url = concat_url(url, params[:convert] ? "?convert=true" : "?convert=false") initial_response = request(method, initial_full_url, :header => default_initial_header.merge(params[:header] || {}), :data => initial_xml, :auth => :writely, :response_type => :response) upload_url = initial_response["location"] if total_bytes > 0 sent_bytes = 0 while data = io.read(UPLOAD_CHUNK_SIZE) content_range = "bytes %d-%d/%d" % [ sent_bytes, sent_bytes + data.bytesize - 1, total_bytes, ] upload_header = { "Content-Type" => content_type, "Content-Range" => content_range, } doc = request( :put, upload_url, :header => upload_header, :data => data, :auth => :writely) sent_bytes += data.bytesize end else upload_header = { "Content-Type" => content_type, } doc = request( :put, upload_url, :header => upload_header, :data => "", :auth => :writely) end return doc.root end |
#worksheet_by_url(url) ⇒ Object
Returns GoogleDrive::Worksheet with given url
. You must specify URL of cell-based feed of the worksheet.
e.g.
session.worksheet_by_url(
"http://spreadsheets.google.com/feeds/" +
"cells/pz7XtlQC-PYxNmbBVgyiNWg/od6/private/full")
215 216 217 |
# File 'lib/google_drive/session.rb', line 215 def worksheet_by_url(url) return Worksheet.new(self, nil, url) end |