google_drive 0.3.11 → 1.0.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -7
- data/README.rdoc +27 -10
- data/lib/google_drive/acl.rb +40 -58
- data/lib/google_drive/acl_entry.rb +76 -56
- data/lib/google_drive/api_client_fetcher.rb +49 -0
- data/lib/google_drive/collection.rb +69 -71
- data/lib/google_drive/file.rb +171 -128
- data/lib/google_drive/session.rb +234 -268
- data/lib/google_drive/spreadsheet.rb +19 -163
- data/lib/google_drive/util.rb +126 -17
- data/lib/google_drive/worksheet.rb +108 -80
- data/lib/google_drive.rb +63 -57
- data/lib/google_drive_v1/acl.rb +115 -0
- data/lib/google_drive_v1/acl_entry.rb +100 -0
- data/lib/google_drive_v1/api_client_fetcher.rb +47 -0
- data/lib/google_drive_v1/authentication_error.rb +14 -0
- data/lib/{google_drive → google_drive_v1}/basic_fetcher.rb +1 -1
- data/lib/{google_drive → google_drive_v1}/client_login_fetcher.rb +2 -2
- data/lib/google_drive_v1/collection.rb +167 -0
- data/lib/google_drive_v1/error.rb +12 -0
- data/lib/google_drive_v1/file.rb +258 -0
- data/lib/google_drive_v1/list.rb +119 -0
- data/lib/google_drive_v1/list_row.rb +88 -0
- data/lib/{google_drive → google_drive_v1}/oauth1_fetcher.rb +1 -1
- data/lib/{google_drive → google_drive_v1}/oauth2_fetcher.rb +2 -2
- data/lib/google_drive_v1/record.rb +31 -0
- data/lib/google_drive_v1/session.rb +522 -0
- data/lib/google_drive_v1/spreadsheet.rb +248 -0
- data/lib/google_drive_v1/table.rb +60 -0
- data/lib/google_drive_v1/util.rb +73 -0
- data/lib/google_drive_v1/worksheet.rb +498 -0
- data/lib/google_drive_v1.rb +148 -0
- metadata +112 -77
- data/doc_src/google_drive/acl_entry.rb +0 -33
data/lib/google_drive/session.rb
CHANGED
@@ -8,11 +8,10 @@ require "rubygems"
|
|
8
8
|
require "nokogiri"
|
9
9
|
require "oauth"
|
10
10
|
require "oauth2"
|
11
|
+
require "google/api_client"
|
11
12
|
|
12
13
|
require "google_drive/util"
|
13
|
-
require "google_drive/
|
14
|
-
require "google_drive/oauth1_fetcher"
|
15
|
-
require "google_drive/oauth2_fetcher"
|
14
|
+
require "google_drive/api_client_fetcher"
|
16
15
|
require "google_drive/error"
|
17
16
|
require "google_drive/authentication_error"
|
18
17
|
require "google_drive/spreadsheet"
|
@@ -23,7 +22,7 @@ require "google_drive/file"
|
|
23
22
|
|
24
23
|
module GoogleDrive
|
25
24
|
|
26
|
-
# Use GoogleDrive.
|
25
|
+
# Use GoogleDrive.login_with_oauth or GoogleDrive.saved_session to get
|
27
26
|
# GoogleDrive::Session object.
|
28
27
|
class Session
|
29
28
|
|
@@ -32,133 +31,103 @@ module GoogleDrive
|
|
32
31
|
|
33
32
|
UPLOAD_CHUNK_SIZE = 512 * 1024
|
34
33
|
|
35
|
-
# DEPRECATED: Will be removed in the next version.
|
36
|
-
#
|
37
|
-
# The same as GoogleDrive.login.
|
38
|
-
def self.login(mail, password, proxy = nil)
|
39
|
-
warn(
|
40
|
-
"WARNING: GoogleDrive.login is deprecated and will be removed in the next version. " +
|
41
|
-
"Use GoogleDrive.login_with_oauth instead.")
|
42
|
-
session = Session.new(nil, ClientLoginFetcher.new({}, proxy))
|
43
|
-
session.login(mail, password)
|
44
|
-
return session
|
45
|
-
end
|
46
|
-
|
47
34
|
# The same as GoogleDrive.login_with_oauth.
|
48
|
-
def self.login_with_oauth(
|
49
|
-
|
50
|
-
warn(
|
51
|
-
"WARNING: Specifying a proxy object is deprecated and will not work in the next version. " +
|
52
|
-
"Set ENV[\"http_proxy\"] instead.")
|
53
|
-
end
|
54
|
-
case access_token
|
55
|
-
when OAuth::AccessToken
|
56
|
-
warn(
|
57
|
-
"WARNING: Authorization with OAuth1 is deprecated and will not work in the next version. " +
|
58
|
-
"Use OAuth2 instead.")
|
59
|
-
raise(GoogleDrive::Error, "proxy is not supported with OAuth1.") if proxy
|
60
|
-
fetcher = OAuth1Fetcher.new(access_token)
|
61
|
-
when OAuth2::AccessToken
|
62
|
-
fetcher = OAuth2Fetcher.new(access_token.token, proxy)
|
63
|
-
when String
|
64
|
-
fetcher = OAuth2Fetcher.new(access_token, proxy)
|
65
|
-
else
|
66
|
-
raise(GoogleDrive::Error,
|
67
|
-
"access_token is neither String, OAuth2::Token nor OAuth::Token: %p" % access_token)
|
68
|
-
end
|
69
|
-
return Session.new(nil, fetcher)
|
35
|
+
def self.login_with_oauth(client_or_access_token, proxy = nil)
|
36
|
+
return Session.new(client_or_access_token, proxy)
|
70
37
|
end
|
71
38
|
|
72
|
-
# The same as GoogleDrive.restore_session.
|
73
|
-
def self.restore_session(auth_tokens, proxy = nil)
|
74
|
-
warn(
|
75
|
-
"WARNING: GoogleDrive.restore_session is deprecated and will be removed in the next version. " +
|
76
|
-
"Use GoogleDrive.login_with_oauth instead.")
|
77
|
-
return Session.new(auth_tokens, nil, proxy)
|
78
|
-
end
|
79
|
-
|
80
39
|
# Creates a dummy GoogleDrive::Session object for testing.
|
81
40
|
def self.new_dummy()
|
82
|
-
return Session.new(nil
|
41
|
+
return Session.new(nil)
|
83
42
|
end
|
84
43
|
|
85
|
-
|
86
|
-
def initialize(auth_tokens = nil, fetcher = nil, proxy = nil)
|
87
|
-
if fetcher
|
88
|
-
@fetcher = fetcher
|
89
|
-
else
|
90
|
-
@fetcher = ClientLoginFetcher.new(auth_tokens || {}, proxy)
|
91
|
-
end
|
92
|
-
end
|
44
|
+
def initialize(client_or_access_token, proxy = nil)
|
93
45
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
if !@fetcher.is_a?(ClientLoginFetcher)
|
99
|
-
raise(GoogleDrive::Error,
|
100
|
-
"Cannot call login for session created by login_with_oauth.")
|
101
|
-
end
|
102
|
-
begin
|
103
|
-
@fetcher.auth_tokens = {
|
104
|
-
:wise => authenticate(mail, password, :wise),
|
105
|
-
:writely => authenticate(mail, password, :writely),
|
106
|
-
}
|
107
|
-
rescue GoogleDrive::Error => ex
|
108
|
-
return true if @on_auth_fail && @on_auth_fail.call()
|
109
|
-
raise(AuthenticationError, "Authentication failed for #{mail}: #{ex.message}")
|
46
|
+
if proxy
|
47
|
+
raise(
|
48
|
+
ArgumentError,
|
49
|
+
"Specifying a proxy object is no longer supported. Set ENV[\"http_proxy\"] instead.")
|
110
50
|
end
|
111
|
-
end
|
112
51
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
52
|
+
if client_or_access_token
|
53
|
+
api_client_params = {
|
54
|
+
:application_name => "google_drive Ruby library",
|
55
|
+
:application_version => "0.4.0",
|
56
|
+
}
|
57
|
+
case client_or_access_token
|
58
|
+
when Google::APIClient
|
59
|
+
client = client_or_access_token
|
60
|
+
when String
|
61
|
+
client = Google::APIClient.new(api_client_params)
|
62
|
+
client.authorization.access_token = client_or_access_token
|
63
|
+
when OAuth2::AccessToken
|
64
|
+
client = Google::APIClient.new(api_client_params)
|
65
|
+
client.authorization.access_token = client_or_access_token.token
|
66
|
+
when OAuth::AccessToken
|
67
|
+
raise(
|
68
|
+
ArgumentError,
|
69
|
+
"Passing OAuth::AccessToken to login_with_oauth is no longer supported. " +
|
70
|
+
"You can use OAuth1 by passing Google::APIClient.")
|
71
|
+
else
|
72
|
+
raise(
|
73
|
+
ArgumentError,
|
74
|
+
("client_or_access_token is neither Google::APIClient, " +
|
75
|
+
"String nor OAuth2::AccessToken: %p") %
|
76
|
+
client_or_access_token)
|
77
|
+
end
|
78
|
+
@fetcher = ApiClientFetcher.new(client)
|
79
|
+
else
|
80
|
+
@fetcher = nil
|
121
81
|
end
|
122
|
-
return @fetcher.auth_tokens
|
123
|
-
end
|
124
82
|
|
125
|
-
# Authentication token.
|
126
|
-
def auth_token(auth = :wise)
|
127
|
-
warn(
|
128
|
-
"WARNING: GoogleDrive::Session\#auth_token is deprecated and will be removed in the next version.")
|
129
|
-
return self.auth_tokens[auth]
|
130
83
|
end
|
131
84
|
|
132
85
|
# Proc or Method called when authentication has failed.
|
133
86
|
# When this function returns +true+, it tries again.
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
return @
|
87
|
+
attr_accessor :on_auth_fail
|
88
|
+
|
89
|
+
def execute!(*args) #:nodoc:
|
90
|
+
return @fetcher.client.execute!(*args)
|
138
91
|
end
|
139
92
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
93
|
+
# Returns the Google::APIClient object.
|
94
|
+
def client
|
95
|
+
return @fetcher.client
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns client.discovered_api("drive", "v2").
|
99
|
+
def drive
|
100
|
+
return @fetcher.drive
|
144
101
|
end
|
145
102
|
|
146
103
|
# Returns list of files for the user as array of GoogleDrive::File or its subclass.
|
147
|
-
# You can specify
|
148
|
-
# https://developers.google.com/
|
149
|
-
#
|
150
|
-
# files doesn't return collections unless "showfolders" => true is specified.
|
104
|
+
# You can specify parameters documented at
|
105
|
+
# https://developers.google.com/drive/v2/reference/files/list
|
151
106
|
#
|
152
107
|
# e.g.
|
153
108
|
# session.files
|
154
|
-
# session.files("
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
109
|
+
# session.files("q" => "title = 'hoge'")
|
110
|
+
# session.files("q" => ["title = ?", "hoge"]) # Same as above with a placeholder
|
111
|
+
#
|
112
|
+
# By default, it returns the first 100 files. You can get all files by calling with a block:
|
113
|
+
# session.files do |file|
|
114
|
+
# p file
|
115
|
+
# end
|
116
|
+
# Or passing "pageToken" parameter:
|
117
|
+
# page_token = nil
|
118
|
+
# begin
|
119
|
+
# (files, page_token) = session.files("pageToken" => page_token)
|
120
|
+
# p files
|
121
|
+
# end while page_token
|
122
|
+
def files(params = {}, &block)
|
123
|
+
params = convert_params(params)
|
124
|
+
return execute_paged!(
|
125
|
+
:api_method => self.drive.files.list,
|
126
|
+
:parameters => params,
|
127
|
+
:converter => proc(){ |af| wrap_api_file(af) },
|
128
|
+
&block)
|
160
129
|
end
|
161
|
-
|
130
|
+
|
162
131
|
# Returns GoogleDrive::File or its subclass whose title exactly matches +title+.
|
163
132
|
# Returns nil if not found. If multiple files with the +title+ are found, returns
|
164
133
|
# one of them.
|
@@ -169,36 +138,55 @@ module GoogleDrive
|
|
169
138
|
if title.is_a?(Array)
|
170
139
|
return self.root_collection.file_by_title(title)
|
171
140
|
else
|
172
|
-
return files("
|
141
|
+
return files("q" => ["title = ?", title], "maxResults" => 1)[0]
|
173
142
|
end
|
174
143
|
end
|
175
144
|
|
145
|
+
# Returns GoogleDrive::File or its subclass with a given +id+.
|
146
|
+
def file_by_id(id)
|
147
|
+
api_result = execute!(
|
148
|
+
:api_method => self.drive.files.get,
|
149
|
+
:parameters => { "fileId" => id })
|
150
|
+
return wrap_api_file(api_result.data)
|
151
|
+
end
|
152
|
+
|
153
|
+
# Returns GoogleDrive::File or its subclass with a given +url+. +url+ must be eitehr of:
|
154
|
+
# - URL of the page you open to access a document/spreadsheet in your browser
|
155
|
+
# - URL of worksheet-based feed of a spreadseet
|
156
|
+
def file_by_url(url)
|
157
|
+
return file_by_id(url_to_id(url))
|
158
|
+
end
|
159
|
+
|
176
160
|
# Returns list of spreadsheets for the user as array of GoogleDrive::Spreadsheet.
|
177
161
|
# You can specify query parameters e.g. "title", "title-exact".
|
178
162
|
#
|
179
163
|
# e.g.
|
180
164
|
# session.spreadsheets
|
181
|
-
# session.spreadsheets("
|
182
|
-
# session.spreadsheets("
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
165
|
+
# session.spreadsheets("q" => "title = 'hoge'")
|
166
|
+
# session.spreadsheets("q" => ["title = ?", "hoge"]) # Same as above with a placeholder
|
167
|
+
#
|
168
|
+
# By default, it returns the first 100 spreadsheets. See document of files method for how to get
|
169
|
+
# all spreadsheets.
|
170
|
+
def spreadsheets(params = {}, &block)
|
171
|
+
params = convert_params(params)
|
172
|
+
query = construct_and_query([
|
173
|
+
"mimeType = 'application/vnd.google-apps.spreadsheet'",
|
174
|
+
params["q"],
|
175
|
+
])
|
176
|
+
return files(params.merge({"q" => query}), &block)
|
192
177
|
end
|
193
178
|
|
194
179
|
# Returns GoogleDrive::Spreadsheet with given +key+.
|
195
180
|
#
|
196
181
|
# e.g.
|
197
|
-
# #
|
198
|
-
# session.spreadsheet_by_key("
|
182
|
+
# # https://docs.google.com/spreadsheets/d/1L3-kvwJblyW_TvjYD-7pE-AXxw5_bkb6S_MljuIPVL0/edit
|
183
|
+
# session.spreadsheet_by_key("1L3-kvwJblyW_TvjYD-7pE-AXxw5_bkb6S_MljuIPVL0")
|
199
184
|
def spreadsheet_by_key(key)
|
200
|
-
|
201
|
-
|
185
|
+
file = file_by_id(key)
|
186
|
+
if !file.is_a?(Spreadsheet)
|
187
|
+
raise(GoogleDrive::Error, "The file with the ID is not a spreadsheet: %s" % key)
|
188
|
+
end
|
189
|
+
return file
|
202
190
|
end
|
203
191
|
|
204
192
|
# Returns GoogleDrive::Spreadsheet with given +url+. You must specify either of:
|
@@ -207,32 +195,23 @@ module GoogleDrive
|
|
207
195
|
#
|
208
196
|
# e.g.
|
209
197
|
# session.spreadsheet_by_url(
|
210
|
-
# "https://docs.google.com/
|
198
|
+
# "https://docs.google.com/spreadsheets/d/1L3-kvwJblyW_TvjYD-7pE-AXxw5_bkb6S_MljuIPVL0/edit")
|
211
199
|
# session.spreadsheet_by_url(
|
212
200
|
# "https://spreadsheets.google.com/feeds/" +
|
213
|
-
# "worksheets/
|
201
|
+
# "worksheets/1L3-kvwJblyW_TvjYD-7pE-AXxw5_bkb6S_MljuIPVL0/private/full")
|
214
202
|
def spreadsheet_by_url(url)
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
case uri.path
|
219
|
-
when /\/d\/([^\/]+)/
|
220
|
-
return spreadsheet_by_key($1)
|
221
|
-
when /\/ccc$/
|
222
|
-
if (uri.query || "").split(/&/).find(){ |s| s=~ /^key=(.*)$/ }
|
223
|
-
return spreadsheet_by_key($1)
|
224
|
-
end
|
225
|
-
end
|
203
|
+
file = file_by_url(url)
|
204
|
+
if !file.is_a?(Spreadsheet)
|
205
|
+
raise(GoogleDrive::Error, "The file with the URL is not a spreadsheet: %s" % url)
|
226
206
|
end
|
227
|
-
|
228
|
-
return Spreadsheet.new(self, url)
|
207
|
+
return file
|
229
208
|
end
|
230
209
|
|
231
210
|
# Returns GoogleDrive::Spreadsheet with given +title+.
|
232
211
|
# Returns nil if not found. If multiple spreadsheets with the +title+ are found, returns
|
233
212
|
# one of them.
|
234
213
|
def spreadsheet_by_title(title)
|
235
|
-
return spreadsheets(
|
214
|
+
return spreadsheets("q" => ["title = ?", title], "maxResults" => 1)[0]
|
236
215
|
end
|
237
216
|
|
238
217
|
# Returns GoogleDrive::Worksheet with given +url+.
|
@@ -243,15 +222,24 @@ module GoogleDrive
|
|
243
222
|
# "http://spreadsheets.google.com/feeds/" +
|
244
223
|
# "cells/pz7XtlQC-PYxNmbBVgyiNWg/od6/private/full")
|
245
224
|
def worksheet_by_url(url)
|
246
|
-
|
225
|
+
if !(url =~
|
226
|
+
%r{^https?://spreadsheets.google.com/feeds/cells/(.*)/(.*)/private/full((\?.*)?)$})
|
227
|
+
raise(GoogleDrive::Error, "URL is not a cell-based feed URL: #{url}")
|
228
|
+
end
|
229
|
+
worksheet_feed_url = "https://spreadsheets.google.com/feeds/worksheets/#{$1}/private/full/#{$2}#{$3}"
|
230
|
+
worksheet_feed_entry = request(:get, worksheet_feed_url)
|
231
|
+
return Worksheet.new(self, nil, worksheet_feed_entry)
|
247
232
|
end
|
248
233
|
|
249
234
|
# Returns the root collection.
|
250
235
|
def root_collection
|
251
|
-
return
|
236
|
+
return @root_collection ||= file_by_id("root")
|
252
237
|
end
|
253
238
|
|
254
239
|
# Returns the top-level collections (direct children of the root collection).
|
240
|
+
#
|
241
|
+
# By default, it returns the first 100 collections. See document of files method for how to get
|
242
|
+
# all collections.
|
255
243
|
def collections
|
256
244
|
return self.root_collection.subcollections
|
257
245
|
end
|
@@ -278,40 +266,26 @@ module GoogleDrive
|
|
278
266
|
# "http://docs.google.com/feeds/default/private/full/folder%3A" +
|
279
267
|
# "0B9GfDpQ2pBVUODNmOGE0NjIzMWU3ZC00NmUyLTk5NzEtYaFkZjY1MjAyxjMc")
|
280
268
|
def collection_by_url(url)
|
281
|
-
|
282
|
-
if
|
283
|
-
|
284
|
-
# Looks like a URL of human-readable collection page. Converts to collection feed URL.
|
285
|
-
url = "#{DOCS_BASE_URL}/folder%3A#{$1}"
|
269
|
+
file = file_by_url(url)
|
270
|
+
if !file.is_a?(Collection)
|
271
|
+
raise(GoogleDrive::Error, "The file with the URL is not a collection: %s" % url)
|
286
272
|
end
|
287
|
-
return
|
273
|
+
return file
|
288
274
|
end
|
289
275
|
|
290
276
|
# Creates new spreadsheet and returns the new GoogleDrive::Spreadsheet.
|
291
277
|
#
|
292
278
|
# e.g.
|
293
279
|
# session.create_spreadsheet("My new sheet")
|
294
|
-
def create_spreadsheet(
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
scheme="http://schemas.google.com/g/2005#kind"
|
304
|
-
term="http://schemas.google.com/docs/2007#spreadsheet"
|
305
|
-
label="spreadsheet"/>
|
306
|
-
<atom:title>#{h(title)}</atom:title>
|
307
|
-
</atom:entry>
|
308
|
-
EOS
|
309
|
-
|
310
|
-
doc = request(:post, feed_url, :data => xml, :auth => :writely)
|
311
|
-
ss_url = doc.css(
|
312
|
-
"link[rel='http://schemas.google.com/spreadsheets/2006#worksheetsfeed']")[0]["href"]
|
313
|
-
return Spreadsheet.new(self, ss_url, title)
|
314
|
-
|
280
|
+
def create_spreadsheet(title = "Untitled")
|
281
|
+
file = self.drive.files.insert.request_schema.new({
|
282
|
+
"title" => title,
|
283
|
+
"mimeType" => "application/vnd.google-apps.spreadsheet",
|
284
|
+
})
|
285
|
+
api_result = execute!(
|
286
|
+
:api_method => self.drive.files.insert,
|
287
|
+
:body_object => file)
|
288
|
+
return wrap_api_file(api_result.data)
|
315
289
|
end
|
316
290
|
|
317
291
|
# Uploads a file with the given +title+ and +content+.
|
@@ -330,7 +304,8 @@ module GoogleDrive
|
|
330
304
|
# session.upload_from_string("hoge\tfoo\n", "Hoge", :content_type => "text/tab-separated-values")
|
331
305
|
# session.upload_from_string("hoge,foo\n", "Hoge", :content_type => "text/tsv")
|
332
306
|
def upload_from_string(content, title = "Untitled", params = {})
|
333
|
-
|
307
|
+
media = new_upload_io(StringIO.new(content), params)
|
308
|
+
return upload_from_media(media, title, params)
|
334
309
|
end
|
335
310
|
|
336
311
|
# Uploads a local file.
|
@@ -347,113 +322,89 @@ module GoogleDrive
|
|
347
322
|
# session.upload_from_file("/path/to/hoge", "Hoge", :content_type => "text/plain")
|
348
323
|
#
|
349
324
|
# # Uploads a text file and converts to a Google Spreadsheet:
|
350
|
-
# session.upload_from_file("/path/to/hoge.tsv", "Hoge")
|
351
325
|
# session.upload_from_file("/path/to/hoge.csv", "Hoge")
|
352
|
-
# session.upload_from_file("/path/to/hoge", "Hoge", :content_type => "text/tab-separated-values")
|
353
326
|
# session.upload_from_file("/path/to/hoge", "Hoge", :content_type => "text/csv")
|
354
327
|
def upload_from_file(path, title = nil, params = {})
|
355
328
|
file_name = ::File.basename(path)
|
356
329
|
params = {:file_name => file_name}.merge(params)
|
357
|
-
|
358
|
-
|
359
|
-
end
|
330
|
+
media = new_upload_io(path, params)
|
331
|
+
return upload_from_media(media, title || file_name, params)
|
360
332
|
end
|
361
|
-
|
333
|
+
|
362
334
|
# Uploads a file. Reads content from +io+.
|
363
335
|
# Returns a GoogleSpreadsheet::File object.
|
364
336
|
def upload_from_io(io, title = "Untitled", params = {})
|
365
|
-
|
366
|
-
|
367
|
-
initial_url = doc.css(
|
368
|
-
"link[rel='http://schemas.google.com/g/2005#resumable-create-media']")[0]["href"]
|
369
|
-
entry = upload_raw(:post, initial_url, io, title, params)
|
370
|
-
return entry_element_to_file(entry)
|
337
|
+
media = new_upload_io(io, params)
|
338
|
+
return upload_from_media(media, title, params)
|
371
339
|
end
|
372
340
|
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
341
|
+
# Uploads a file. Reads content from +media+.
|
342
|
+
# Returns a GoogleSpreadsheet::File object.
|
343
|
+
def upload_from_media(media, title = "Untitled", params = {})
|
344
|
+
file = self.drive.files.insert.request_schema.new({
|
345
|
+
"title" => title,
|
346
|
+
})
|
347
|
+
api_result = execute!(
|
348
|
+
:api_method => self.drive.files.insert,
|
349
|
+
:body_object => file,
|
350
|
+
:media => media,
|
351
|
+
:parameters => {
|
352
|
+
"uploadType" => "multipart",
|
353
|
+
"convert" => params[:convert] == false ? "false" : "true",
|
354
|
+
})
|
355
|
+
return wrap_api_file(api_result.data)
|
356
|
+
end
|
357
|
+
|
358
|
+
def wrap_api_file(api_file) #:nodoc:
|
359
|
+
case api_file.mime_type
|
360
|
+
when "application/vnd.google-apps.folder"
|
361
|
+
return Collection.new(self, api_file)
|
362
|
+
when "application/vnd.google-apps.spreadsheet"
|
363
|
+
return Spreadsheet.new(self, api_file)
|
364
|
+
else
|
365
|
+
return File.new(self, api_file)
|
386
366
|
end
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
if total_bytes > 0
|
409
|
-
sent_bytes = 0
|
410
|
-
while data = io.read(UPLOAD_CHUNK_SIZE)
|
411
|
-
content_range = "bytes %d-%d/%d" % [
|
412
|
-
sent_bytes,
|
413
|
-
sent_bytes + data.bytesize - 1,
|
414
|
-
total_bytes,
|
415
|
-
]
|
416
|
-
upload_header = {
|
417
|
-
"Content-Type" => content_type,
|
418
|
-
"Content-Range" => content_range,
|
419
|
-
}
|
420
|
-
doc = request(
|
421
|
-
:put, upload_url, :header => upload_header, :data => data, :auth => :writely)
|
422
|
-
sent_bytes += data.bytesize
|
367
|
+
end
|
368
|
+
|
369
|
+
def execute_paged!(opts, &block) #:nodoc:
|
370
|
+
|
371
|
+
if block
|
372
|
+
|
373
|
+
page_token = nil
|
374
|
+
begin
|
375
|
+
parameters = (opts[:parameters] || {}).merge({"pageToken" => page_token})
|
376
|
+
(items, page_token) = execute_paged!(opts.merge({:parameters => parameters}))
|
377
|
+
items.each(&block)
|
378
|
+
end while page_token
|
379
|
+
|
380
|
+
elsif opts[:parameters] && opts[:parameters].has_key?("pageToken")
|
381
|
+
|
382
|
+
api_result = self.execute!(
|
383
|
+
:api_method => opts[:api_method],
|
384
|
+
:parameters => opts[:parameters])
|
385
|
+
items = api_result.data.items.map() do |item|
|
386
|
+
opts[:converter] ? opts[:converter].call(item) : item
|
423
387
|
end
|
388
|
+
return [items, api_result.data.next_page_token]
|
389
|
+
|
424
390
|
else
|
425
|
-
|
426
|
-
|
427
|
-
}
|
428
|
-
|
429
|
-
|
391
|
+
|
392
|
+
parameters = (opts[:parameters] || {}).merge({"pageToken" => nil})
|
393
|
+
(items, next_page_token) = execute_paged!(opts.merge({:parameters => parameters}))
|
394
|
+
return items
|
395
|
+
|
430
396
|
end
|
431
397
|
|
432
|
-
return doc.root
|
433
|
-
|
434
398
|
end
|
435
399
|
|
436
|
-
def entry_element_to_file(entry) #:nodoc:
|
437
|
-
type, resource_id = entry.css("gd|resourceId").text.split(/:/)
|
438
|
-
title = entry.css("title").text
|
439
|
-
case type
|
440
|
-
when "folder"
|
441
|
-
return Collection.new(self, entry)
|
442
|
-
when "spreadsheet"
|
443
|
-
worksheets_feed_link = entry.css(
|
444
|
-
"link[rel='http://schemas.google.com/spreadsheets/2006#worksheetsfeed']")[0]
|
445
|
-
return Spreadsheet.new(self, worksheets_feed_link["href"], title)
|
446
|
-
else
|
447
|
-
return GoogleDrive::File.new(self, entry)
|
448
|
-
end
|
449
|
-
end
|
450
|
-
|
451
400
|
def request(method, url, params = {}) #:nodoc:
|
452
401
|
|
453
402
|
# Always uses HTTPS.
|
454
403
|
url = url.gsub(%r{^http://}, "https://")
|
455
404
|
data = params[:data]
|
456
405
|
auth = params[:auth] || :wise
|
406
|
+
response_type = params[:response_type] || :xml
|
407
|
+
|
457
408
|
if params[:header]
|
458
409
|
extra_header = params[:header]
|
459
410
|
elsif data
|
@@ -461,7 +412,7 @@ module GoogleDrive
|
|
461
412
|
else
|
462
413
|
extra_header = {}
|
463
414
|
end
|
464
|
-
|
415
|
+
extra_header = {"GData-Version" => "3.0"}.merge(extra_header)
|
465
416
|
|
466
417
|
while true
|
467
418
|
response = @fetcher.request_raw(method, url, data, extra_header, auth)
|
@@ -499,22 +450,37 @@ module GoogleDrive
|
|
499
450
|
end
|
500
451
|
end
|
501
452
|
|
502
|
-
def
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
453
|
+
def url_to_id(url)
|
454
|
+
uri = URI.parse(url)
|
455
|
+
if ["spreadsheets.google.com", "docs.google.com", "drive.google.com"].include?(uri.host)
|
456
|
+
case uri.path
|
457
|
+
# Document feed.
|
458
|
+
when /^\/feeds\/\w+\/private\/full\/\w+%3A(.*)$/
|
459
|
+
return $1
|
460
|
+
# Worksheets feed of a spreadsheet.
|
461
|
+
when /^\/feeds\/worksheets\/([^\/]+)/
|
462
|
+
return $1
|
463
|
+
# Human-readable new spreadsheet/document.
|
464
|
+
when /\/d\/([^\/]+)/
|
465
|
+
return $1
|
466
|
+
# Human-readable folder view.
|
467
|
+
when /\/folderview$/
|
468
|
+
if (uri.query || "").split(/&/).find(){ |s| s=~ /^id=(.*)$/ }
|
469
|
+
return $1
|
470
|
+
end
|
471
|
+
# Human-readable old spreadsheet.
|
472
|
+
when /\/ccc$/
|
473
|
+
if (uri.query || "").split(/&/).find(){ |s| s=~ /^key=(.*)$/ }
|
474
|
+
return $1
|
475
|
+
end
|
476
|
+
end
|
477
|
+
case uri.fragment
|
478
|
+
# Human-readable collection page.
|
479
|
+
when /^folders\/(.+)$/
|
480
|
+
return $1
|
481
|
+
end
|
482
|
+
end
|
483
|
+
raise(GoogleDrive::Error, "The given URL is not a known Google Drive URL: %s" % url)
|
518
484
|
end
|
519
485
|
|
520
486
|
end
|