google_drive 0.3.11 → 1.0.0.pre1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|