OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/drive/drive_api_service.h" | |
6 | |
7 #include <string> | |
8 #include <vector> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/strings/stringprintf.h" | |
12 #include "chrome/browser/drive/drive_api_util.h" | |
13 #include "google_apis/drive/auth_service.h" | |
14 #include "google_apis/drive/drive_api_parser.h" | |
15 #include "google_apis/drive/drive_api_requests.h" | |
16 #include "google_apis/drive/request_sender.h" | |
17 #include "google_apis/google_api_keys.h" | |
18 #include "net/url_request/url_request_context_getter.h" | |
19 | |
20 using google_apis::AboutResourceCallback; | |
21 using google_apis::AppList; | |
22 using google_apis::AppListCallback; | |
23 using google_apis::AuthStatusCallback; | |
24 using google_apis::AuthorizeAppCallback; | |
25 using google_apis::CancelCallback; | |
26 using google_apis::ChangeList; | |
27 using google_apis::ChangeListCallback; | |
28 using google_apis::DownloadActionCallback; | |
29 using google_apis::EntryActionCallback; | |
30 using google_apis::FileList; | |
31 using google_apis::FileListCallback; | |
32 using google_apis::FileResource; | |
33 using google_apis::FileResourceCallback; | |
34 using google_apis::DRIVE_OTHER_ERROR; | |
35 using google_apis::DRIVE_PARSE_ERROR; | |
36 using google_apis::DriveApiErrorCode; | |
37 using google_apis::GetContentCallback; | |
38 using google_apis::GetShareUrlCallback; | |
39 using google_apis::HTTP_NOT_IMPLEMENTED; | |
40 using google_apis::HTTP_SUCCESS; | |
41 using google_apis::InitiateUploadCallback; | |
42 using google_apis::ProgressCallback; | |
43 using google_apis::RequestSender; | |
44 using google_apis::UploadRangeResponse; | |
45 using google_apis::drive::AboutGetRequest; | |
46 using google_apis::drive::AppsListRequest; | |
47 using google_apis::drive::ChangesListRequest; | |
48 using google_apis::drive::ChangesListNextPageRequest; | |
49 using google_apis::drive::ChildrenDeleteRequest; | |
50 using google_apis::drive::ChildrenInsertRequest; | |
51 using google_apis::drive::DownloadFileRequest; | |
52 using google_apis::drive::FilesCopyRequest; | |
53 using google_apis::drive::FilesGetRequest; | |
54 using google_apis::drive::FilesInsertRequest; | |
55 using google_apis::drive::FilesPatchRequest; | |
56 using google_apis::drive::FilesListRequest; | |
57 using google_apis::drive::FilesListNextPageRequest; | |
58 using google_apis::drive::FilesDeleteRequest; | |
59 using google_apis::drive::FilesTrashRequest; | |
60 using google_apis::drive::GetUploadStatusRequest; | |
61 using google_apis::drive::InitiateUploadExistingFileRequest; | |
62 using google_apis::drive::InitiateUploadNewFileRequest; | |
63 using google_apis::drive::ResumeUploadRequest; | |
64 using google_apis::drive::UploadRangeCallback; | |
65 | |
66 namespace drive { | |
67 | |
68 namespace { | |
69 | |
70 // OAuth2 scopes for Drive API. | |
71 const char kDriveScope[] = "https://www.googleapis.com/auth/drive"; | |
72 const char kDriveAppsReadonlyScope[] = | |
73 "https://www.googleapis.com/auth/drive.apps.readonly"; | |
74 const char kDriveAppsScope[] = "https://www.googleapis.com/auth/drive.apps"; | |
75 const char kDocsListScope[] = "https://docs.google.com/feeds/"; | |
76 | |
77 // Mime type to create a directory. | |
78 const char kFolderMimeType[] = "application/vnd.google-apps.folder"; | |
79 | |
80 // Max number of file entries to be fetched in a single http request. | |
81 // | |
82 // The larger the number is, | |
83 // - The total running time to fetch the whole file list will become shorter. | |
84 // - The running time for a single request tends to become longer. | |
85 // Since the file list fetching is a completely background task, for our side, | |
86 // only the total time matters. However, the server seems to have a time limit | |
87 // per single request, which disables us to set the largest value (1000). | |
88 // TODO(kinaba): make it larger when the server gets faster. | |
89 const int kMaxNumFilesResourcePerRequest = 300; | |
90 const int kMaxNumFilesResourcePerRequestForSearch = 100; | |
91 | |
92 // For performance, we declare all fields we use. | |
93 const char kAboutResourceFields[] = | |
94 "kind,quotaBytesTotal,quotaBytesUsedAggregate,largestChangeId,rootFolderId"; | |
95 const char kFileResourceFields[] = | |
96 "kind,id,title,createdDate,sharedWithMeDate,mimeType," | |
97 "md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width," | |
98 "imageMediaMetadata/height,imageMediaMetadata/rotation,etag," | |
99 "parents(id,parentLink),alternateLink," | |
100 "modifiedDate,lastViewedByMeDate,shared"; | |
101 const char kFileResourceOpenWithLinksFields[] = | |
102 "kind,id,openWithLinks/*"; | |
103 const char kFileResourceShareLinkFields[] = | |
104 "kind,id,shareLink"; | |
105 const char kFileListFields[] = | |
106 "kind,items(kind,id,title,createdDate,sharedWithMeDate," | |
107 "mimeType,md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width," | |
108 "imageMediaMetadata/height,imageMediaMetadata/rotation,etag," | |
109 "parents(id,parentLink),alternateLink," | |
110 "modifiedDate,lastViewedByMeDate,shared),nextLink"; | |
111 const char kChangeListFields[] = | |
112 "kind,items(file(kind,id,title,createdDate,sharedWithMeDate," | |
113 "mimeType,md5Checksum,fileSize,labels/trashed,imageMediaMetadata/width," | |
114 "imageMediaMetadata/height,imageMediaMetadata/rotation,etag," | |
115 "parents(id,parentLink),alternateLink,modifiedDate," | |
116 "lastViewedByMeDate,shared),deleted,id,fileId,modificationDate),nextLink," | |
117 "largestChangeId"; | |
118 | |
119 void ExtractOpenUrlAndRun(const std::string& app_id, | |
120 const AuthorizeAppCallback& callback, | |
121 DriveApiErrorCode error, | |
122 scoped_ptr<FileResource> value) { | |
123 DCHECK(!callback.is_null()); | |
124 | |
125 if (!value) { | |
126 callback.Run(error, GURL()); | |
127 return; | |
128 } | |
129 | |
130 const std::vector<FileResource::OpenWithLink>& open_with_links = | |
131 value->open_with_links(); | |
132 for (size_t i = 0; i < open_with_links.size(); ++i) { | |
133 if (open_with_links[i].app_id == app_id) { | |
134 callback.Run(HTTP_SUCCESS, open_with_links[i].open_url); | |
135 return; | |
136 } | |
137 } | |
138 | |
139 // Not found. | |
140 callback.Run(DRIVE_OTHER_ERROR, GURL()); | |
141 } | |
142 | |
143 void ExtractShareUrlAndRun(const GetShareUrlCallback& callback, | |
144 DriveApiErrorCode error, | |
145 scoped_ptr<FileResource> value) { | |
146 callback.Run(error, value ? value->share_link() : GURL()); | |
147 } | |
148 | |
149 // Ignores the |entry|, and runs the |callback|. | |
150 void EntryActionCallbackAdapter( | |
151 const EntryActionCallback& callback, | |
152 DriveApiErrorCode error, scoped_ptr<FileResource> entry) { | |
153 callback.Run(error); | |
154 } | |
155 | |
156 // The resource ID for the root directory for Drive API is defined in the spec: | |
157 // https://developers.google.com/drive/folder | |
158 const char kDriveApiRootDirectoryResourceId[] = "root"; | |
159 | |
160 } // namespace | |
161 | |
162 BatchRequestConfigurator::BatchRequestConfigurator( | |
163 const base::WeakPtr<google_apis::drive::BatchUploadRequest>& batch_request, | |
164 const google_apis::CancelCallback& cancel_callback) | |
165 : batch_request_(batch_request), cancel_callback_(cancel_callback) { | |
166 } | |
167 | |
168 BatchRequestConfigurator::~BatchRequestConfigurator() { | |
169 // The batch requst has not been committed. | |
170 if (batch_request_) | |
171 cancel_callback_.Run(); | |
172 } | |
173 | |
174 google_apis::CancelCallback BatchRequestConfigurator::MultipartUploadNewFile( | |
175 const std::string& content_type, | |
176 int64 content_length, | |
177 const std::string& parent_resource_id, | |
178 const std::string& title, | |
179 const base::FilePath& local_file_path, | |
180 const UploadNewFileOptions& options, | |
181 const google_apis::FileResourceCallback& callback, | |
182 const google_apis::ProgressCallback& progress_callback) { | |
183 DCHECK(CalledOnValidThread()); | |
184 DCHECK(!callback.is_null()); | |
185 | |
186 DCHECK(batch_request_); | |
187 | |
188 batch_request_->AddRequest( | |
189 new google_apis::drive::MultipartUploadNewFileDelegate( | |
190 batch_request_->sender(), title, parent_resource_id, content_type, | |
191 content_length, options.modified_date, options.last_viewed_by_me_date, | |
192 local_file_path, options.properties, batch_request_->url_generator(), | |
193 callback, progress_callback)); | |
194 return cancel_callback_; | |
195 } | |
196 | |
197 google_apis::CancelCallback | |
198 BatchRequestConfigurator::MultipartUploadExistingFile( | |
199 const std::string& content_type, | |
200 int64 content_length, | |
201 const std::string& resource_id, | |
202 const base::FilePath& local_file_path, | |
203 const UploadExistingFileOptions& options, | |
204 const google_apis::FileResourceCallback& callback, | |
205 const google_apis::ProgressCallback& progress_callback) { | |
206 DCHECK(CalledOnValidThread()); | |
207 DCHECK(!callback.is_null()); | |
208 DCHECK(batch_request_); | |
209 | |
210 batch_request_->AddRequest( | |
211 new google_apis::drive::MultipartUploadExistingFileDelegate( | |
212 batch_request_->sender(), options.title, resource_id, | |
213 options.parent_resource_id, content_type, content_length, | |
214 options.modified_date, options.last_viewed_by_me_date, | |
215 local_file_path, options.etag, options.properties, | |
216 batch_request_->url_generator(), callback, progress_callback)); | |
217 return cancel_callback_; | |
218 } | |
219 | |
220 void BatchRequestConfigurator::Commit() { | |
221 DCHECK(CalledOnValidThread()); | |
222 if (!batch_request_) | |
223 return; | |
224 batch_request_->Commit(); | |
225 batch_request_.reset(); | |
226 } | |
227 | |
228 DriveAPIService::DriveAPIService( | |
229 OAuth2TokenService* oauth2_token_service, | |
230 net::URLRequestContextGetter* url_request_context_getter, | |
231 base::SequencedTaskRunner* blocking_task_runner, | |
232 const GURL& base_url, | |
233 const GURL& base_download_url, | |
234 const std::string& custom_user_agent) | |
235 : oauth2_token_service_(oauth2_token_service), | |
236 url_request_context_getter_(url_request_context_getter), | |
237 blocking_task_runner_(blocking_task_runner), | |
238 url_generator_(base_url, base_download_url), | |
239 custom_user_agent_(custom_user_agent) { | |
240 } | |
241 | |
242 DriveAPIService::~DriveAPIService() { | |
243 DCHECK(thread_checker_.CalledOnValidThread()); | |
244 if (sender_.get()) | |
245 sender_->auth_service()->RemoveObserver(this); | |
246 } | |
247 | |
248 void DriveAPIService::Initialize(const std::string& account_id) { | |
249 DCHECK(thread_checker_.CalledOnValidThread()); | |
250 | |
251 std::vector<std::string> scopes; | |
252 scopes.push_back(kDriveScope); | |
253 scopes.push_back(kDriveAppsReadonlyScope); | |
254 scopes.push_back(kDriveAppsScope); | |
255 | |
256 // Note: The following scope is used to support GetShareUrl on Drive API v2. | |
257 // Unfortunately, there is no support on Drive API v2, so we need to fall back | |
258 // to GData WAPI for the GetShareUrl. | |
259 scopes.push_back(kDocsListScope); | |
260 | |
261 sender_.reset(new RequestSender( | |
262 new google_apis::AuthService(oauth2_token_service_, | |
263 account_id, | |
264 url_request_context_getter_.get(), | |
265 scopes), | |
266 url_request_context_getter_.get(), | |
267 blocking_task_runner_.get(), | |
268 custom_user_agent_)); | |
269 sender_->auth_service()->AddObserver(this); | |
270 } | |
271 | |
272 void DriveAPIService::AddObserver(DriveServiceObserver* observer) { | |
273 observers_.AddObserver(observer); | |
274 } | |
275 | |
276 void DriveAPIService::RemoveObserver(DriveServiceObserver* observer) { | |
277 observers_.RemoveObserver(observer); | |
278 } | |
279 | |
280 bool DriveAPIService::CanSendRequest() const { | |
281 DCHECK(thread_checker_.CalledOnValidThread()); | |
282 | |
283 return HasRefreshToken(); | |
284 } | |
285 | |
286 std::string DriveAPIService::GetRootResourceId() const { | |
287 return kDriveApiRootDirectoryResourceId; | |
288 } | |
289 | |
290 CancelCallback DriveAPIService::GetAllFileList( | |
291 const FileListCallback& callback) { | |
292 DCHECK(thread_checker_.CalledOnValidThread()); | |
293 DCHECK(!callback.is_null()); | |
294 | |
295 FilesListRequest* request = new FilesListRequest( | |
296 sender_.get(), url_generator_, callback); | |
297 request->set_max_results(kMaxNumFilesResourcePerRequest); | |
298 request->set_q("trashed = false"); // Exclude trashed files. | |
299 request->set_fields(kFileListFields); | |
300 return sender_->StartRequestWithRetry(request); | |
301 } | |
302 | |
303 CancelCallback DriveAPIService::GetFileListInDirectory( | |
304 const std::string& directory_resource_id, | |
305 const FileListCallback& callback) { | |
306 DCHECK(thread_checker_.CalledOnValidThread()); | |
307 DCHECK(!directory_resource_id.empty()); | |
308 DCHECK(!callback.is_null()); | |
309 | |
310 // Because children.list method on Drive API v2 returns only the list of | |
311 // children's references, but we need all file resource list. | |
312 // So, here we use files.list method instead, with setting parents query. | |
313 // After the migration from GData WAPI to Drive API v2, we should clean the | |
314 // code up by moving the responsibility to include "parents" in the query | |
315 // to client side. | |
316 // We aren't interested in files in trash in this context, neither. | |
317 FilesListRequest* request = new FilesListRequest( | |
318 sender_.get(), url_generator_, callback); | |
319 request->set_max_results(kMaxNumFilesResourcePerRequest); | |
320 request->set_q(base::StringPrintf( | |
321 "'%s' in parents and trashed = false", | |
322 util::EscapeQueryStringValue(directory_resource_id).c_str())); | |
323 request->set_fields(kFileListFields); | |
324 return sender_->StartRequestWithRetry(request); | |
325 } | |
326 | |
327 CancelCallback DriveAPIService::Search( | |
328 const std::string& search_query, | |
329 const FileListCallback& callback) { | |
330 DCHECK(thread_checker_.CalledOnValidThread()); | |
331 DCHECK(!search_query.empty()); | |
332 DCHECK(!callback.is_null()); | |
333 | |
334 FilesListRequest* request = new FilesListRequest( | |
335 sender_.get(), url_generator_, callback); | |
336 request->set_max_results(kMaxNumFilesResourcePerRequestForSearch); | |
337 request->set_q(util::TranslateQuery(search_query)); | |
338 request->set_fields(kFileListFields); | |
339 return sender_->StartRequestWithRetry(request); | |
340 } | |
341 | |
342 CancelCallback DriveAPIService::SearchByTitle( | |
343 const std::string& title, | |
344 const std::string& directory_resource_id, | |
345 const FileListCallback& callback) { | |
346 DCHECK(thread_checker_.CalledOnValidThread()); | |
347 DCHECK(!title.empty()); | |
348 DCHECK(!callback.is_null()); | |
349 | |
350 std::string query; | |
351 base::StringAppendF(&query, "title = '%s'", | |
352 util::EscapeQueryStringValue(title).c_str()); | |
353 if (!directory_resource_id.empty()) { | |
354 base::StringAppendF( | |
355 &query, " and '%s' in parents", | |
356 util::EscapeQueryStringValue(directory_resource_id).c_str()); | |
357 } | |
358 query += " and trashed = false"; | |
359 | |
360 FilesListRequest* request = new FilesListRequest( | |
361 sender_.get(), url_generator_, callback); | |
362 request->set_max_results(kMaxNumFilesResourcePerRequest); | |
363 request->set_q(query); | |
364 request->set_fields(kFileListFields); | |
365 return sender_->StartRequestWithRetry(request); | |
366 } | |
367 | |
368 CancelCallback DriveAPIService::GetChangeList( | |
369 int64 start_changestamp, | |
370 const ChangeListCallback& callback) { | |
371 DCHECK(thread_checker_.CalledOnValidThread()); | |
372 DCHECK(!callback.is_null()); | |
373 | |
374 ChangesListRequest* request = new ChangesListRequest( | |
375 sender_.get(), url_generator_, callback); | |
376 request->set_max_results(kMaxNumFilesResourcePerRequest); | |
377 request->set_start_change_id(start_changestamp); | |
378 request->set_fields(kChangeListFields); | |
379 return sender_->StartRequestWithRetry(request); | |
380 } | |
381 | |
382 CancelCallback DriveAPIService::GetRemainingChangeList( | |
383 const GURL& next_link, | |
384 const ChangeListCallback& callback) { | |
385 DCHECK(thread_checker_.CalledOnValidThread()); | |
386 DCHECK(!next_link.is_empty()); | |
387 DCHECK(!callback.is_null()); | |
388 | |
389 ChangesListNextPageRequest* request = new ChangesListNextPageRequest( | |
390 sender_.get(), callback); | |
391 request->set_next_link(next_link); | |
392 request->set_fields(kChangeListFields); | |
393 return sender_->StartRequestWithRetry(request); | |
394 } | |
395 | |
396 CancelCallback DriveAPIService::GetRemainingFileList( | |
397 const GURL& next_link, | |
398 const FileListCallback& callback) { | |
399 DCHECK(thread_checker_.CalledOnValidThread()); | |
400 DCHECK(!next_link.is_empty()); | |
401 DCHECK(!callback.is_null()); | |
402 | |
403 FilesListNextPageRequest* request = new FilesListNextPageRequest( | |
404 sender_.get(), callback); | |
405 request->set_next_link(next_link); | |
406 request->set_fields(kFileListFields); | |
407 return sender_->StartRequestWithRetry(request); | |
408 } | |
409 | |
410 CancelCallback DriveAPIService::GetFileResource( | |
411 const std::string& resource_id, | |
412 const FileResourceCallback& callback) { | |
413 DCHECK(thread_checker_.CalledOnValidThread()); | |
414 DCHECK(!callback.is_null()); | |
415 | |
416 FilesGetRequest* request = new FilesGetRequest( | |
417 sender_.get(), url_generator_, google_apis::IsGoogleChromeAPIKeyUsed(), | |
418 callback); | |
419 request->set_file_id(resource_id); | |
420 request->set_fields(kFileResourceFields); | |
421 return sender_->StartRequestWithRetry(request); | |
422 } | |
423 | |
424 CancelCallback DriveAPIService::GetShareUrl( | |
425 const std::string& resource_id, | |
426 const GURL& embed_origin, | |
427 const GetShareUrlCallback& callback) { | |
428 DCHECK(thread_checker_.CalledOnValidThread()); | |
429 DCHECK(!callback.is_null()); | |
430 | |
431 if (!google_apis::IsGoogleChromeAPIKeyUsed()) { | |
432 LOG(ERROR) << "Only the official build of Chrome OS can open share dialogs " | |
433 << "from the file manager."; | |
434 } | |
435 | |
436 FilesGetRequest* request = new FilesGetRequest( | |
437 sender_.get(), url_generator_, google_apis::IsGoogleChromeAPIKeyUsed(), | |
438 base::Bind(&ExtractShareUrlAndRun, callback)); | |
439 request->set_file_id(resource_id); | |
440 request->set_fields(kFileResourceShareLinkFields); | |
441 request->set_embed_origin(embed_origin); | |
442 return sender_->StartRequestWithRetry(request); | |
443 } | |
444 | |
445 CancelCallback DriveAPIService::GetAboutResource( | |
446 const AboutResourceCallback& callback) { | |
447 DCHECK(thread_checker_.CalledOnValidThread()); | |
448 DCHECK(!callback.is_null()); | |
449 | |
450 AboutGetRequest* request = | |
451 new AboutGetRequest(sender_.get(), url_generator_, callback); | |
452 request->set_fields(kAboutResourceFields); | |
453 return sender_->StartRequestWithRetry(request); | |
454 } | |
455 | |
456 CancelCallback DriveAPIService::GetAppList(const AppListCallback& callback) { | |
457 DCHECK(thread_checker_.CalledOnValidThread()); | |
458 DCHECK(!callback.is_null()); | |
459 | |
460 return sender_->StartRequestWithRetry( | |
461 new AppsListRequest(sender_.get(), url_generator_, | |
462 google_apis::IsGoogleChromeAPIKeyUsed(), | |
463 callback)); | |
464 } | |
465 | |
466 CancelCallback DriveAPIService::DownloadFile( | |
467 const base::FilePath& local_cache_path, | |
468 const std::string& resource_id, | |
469 const DownloadActionCallback& download_action_callback, | |
470 const GetContentCallback& get_content_callback, | |
471 const ProgressCallback& progress_callback) { | |
472 DCHECK(thread_checker_.CalledOnValidThread()); | |
473 DCHECK(!download_action_callback.is_null()); | |
474 // get_content_callback may be null. | |
475 | |
476 return sender_->StartRequestWithRetry( | |
477 new DownloadFileRequest(sender_.get(), | |
478 url_generator_, | |
479 resource_id, | |
480 local_cache_path, | |
481 download_action_callback, | |
482 get_content_callback, | |
483 progress_callback)); | |
484 } | |
485 | |
486 CancelCallback DriveAPIService::DeleteResource( | |
487 const std::string& resource_id, | |
488 const std::string& etag, | |
489 const EntryActionCallback& callback) { | |
490 DCHECK(thread_checker_.CalledOnValidThread()); | |
491 DCHECK(!callback.is_null()); | |
492 | |
493 FilesDeleteRequest* request = new FilesDeleteRequest( | |
494 sender_.get(), url_generator_, callback); | |
495 request->set_file_id(resource_id); | |
496 request->set_etag(etag); | |
497 return sender_->StartRequestWithRetry(request); | |
498 } | |
499 | |
500 CancelCallback DriveAPIService::TrashResource( | |
501 const std::string& resource_id, | |
502 const EntryActionCallback& callback) { | |
503 DCHECK(thread_checker_.CalledOnValidThread()); | |
504 DCHECK(!callback.is_null()); | |
505 | |
506 FilesTrashRequest* request = new FilesTrashRequest( | |
507 sender_.get(), url_generator_, | |
508 base::Bind(&EntryActionCallbackAdapter, callback)); | |
509 request->set_file_id(resource_id); | |
510 request->set_fields(kFileResourceFields); | |
511 return sender_->StartRequestWithRetry(request); | |
512 } | |
513 | |
514 CancelCallback DriveAPIService::AddNewDirectory( | |
515 const std::string& parent_resource_id, | |
516 const std::string& directory_title, | |
517 const AddNewDirectoryOptions& options, | |
518 const FileResourceCallback& callback) { | |
519 DCHECK(thread_checker_.CalledOnValidThread()); | |
520 DCHECK(!callback.is_null()); | |
521 | |
522 FilesInsertRequest* request = new FilesInsertRequest( | |
523 sender_.get(), url_generator_, callback); | |
524 request->set_last_viewed_by_me_date(options.last_viewed_by_me_date); | |
525 request->set_mime_type(kFolderMimeType); | |
526 request->set_modified_date(options.modified_date); | |
527 request->add_parent(parent_resource_id); | |
528 request->set_title(directory_title); | |
529 request->set_properties(options.properties); | |
530 request->set_fields(kFileResourceFields); | |
531 return sender_->StartRequestWithRetry(request); | |
532 } | |
533 | |
534 CancelCallback DriveAPIService::CopyResource( | |
535 const std::string& resource_id, | |
536 const std::string& parent_resource_id, | |
537 const std::string& new_title, | |
538 const base::Time& last_modified, | |
539 const FileResourceCallback& callback) { | |
540 DCHECK(thread_checker_.CalledOnValidThread()); | |
541 DCHECK(!callback.is_null()); | |
542 | |
543 FilesCopyRequest* request = new FilesCopyRequest( | |
544 sender_.get(), url_generator_, callback); | |
545 request->set_file_id(resource_id); | |
546 request->add_parent(parent_resource_id); | |
547 request->set_title(new_title); | |
548 request->set_modified_date(last_modified); | |
549 request->set_fields(kFileResourceFields); | |
550 return sender_->StartRequestWithRetry(request); | |
551 } | |
552 | |
553 CancelCallback DriveAPIService::UpdateResource( | |
554 const std::string& resource_id, | |
555 const std::string& parent_resource_id, | |
556 const std::string& new_title, | |
557 const base::Time& last_modified, | |
558 const base::Time& last_viewed_by_me, | |
559 const google_apis::drive::Properties& properties, | |
560 const FileResourceCallback& callback) { | |
561 DCHECK(thread_checker_.CalledOnValidThread()); | |
562 DCHECK(!callback.is_null()); | |
563 | |
564 FilesPatchRequest* request = new FilesPatchRequest( | |
565 sender_.get(), url_generator_, callback); | |
566 request->set_file_id(resource_id); | |
567 request->set_title(new_title); | |
568 if (!parent_resource_id.empty()) | |
569 request->add_parent(parent_resource_id); | |
570 if (!last_modified.is_null()) { | |
571 // Need to set setModifiedDate to true to overwrite modifiedDate. | |
572 request->set_set_modified_date(true); | |
573 request->set_modified_date(last_modified); | |
574 } | |
575 if (!last_viewed_by_me.is_null()) { | |
576 // Need to set updateViewedDate to false, otherwise the lastViewedByMeDate | |
577 // will be set to the request time (not the specified time via request). | |
578 request->set_update_viewed_date(false); | |
579 request->set_last_viewed_by_me_date(last_viewed_by_me); | |
580 } | |
581 request->set_fields(kFileResourceFields); | |
582 request->set_properties(properties); | |
583 return sender_->StartRequestWithRetry(request); | |
584 } | |
585 | |
586 CancelCallback DriveAPIService::AddResourceToDirectory( | |
587 const std::string& parent_resource_id, | |
588 const std::string& resource_id, | |
589 const EntryActionCallback& callback) { | |
590 DCHECK(thread_checker_.CalledOnValidThread()); | |
591 DCHECK(!callback.is_null()); | |
592 | |
593 ChildrenInsertRequest* request = | |
594 new ChildrenInsertRequest(sender_.get(), url_generator_, callback); | |
595 request->set_folder_id(parent_resource_id); | |
596 request->set_id(resource_id); | |
597 return sender_->StartRequestWithRetry(request); | |
598 } | |
599 | |
600 CancelCallback DriveAPIService::RemoveResourceFromDirectory( | |
601 const std::string& parent_resource_id, | |
602 const std::string& resource_id, | |
603 const EntryActionCallback& callback) { | |
604 DCHECK(thread_checker_.CalledOnValidThread()); | |
605 DCHECK(!callback.is_null()); | |
606 | |
607 ChildrenDeleteRequest* request = | |
608 new ChildrenDeleteRequest(sender_.get(), url_generator_, callback); | |
609 request->set_child_id(resource_id); | |
610 request->set_folder_id(parent_resource_id); | |
611 return sender_->StartRequestWithRetry(request); | |
612 } | |
613 | |
614 CancelCallback DriveAPIService::InitiateUploadNewFile( | |
615 const std::string& content_type, | |
616 int64 content_length, | |
617 const std::string& parent_resource_id, | |
618 const std::string& title, | |
619 const UploadNewFileOptions& options, | |
620 const InitiateUploadCallback& callback) { | |
621 DCHECK(thread_checker_.CalledOnValidThread()); | |
622 DCHECK(!callback.is_null()); | |
623 | |
624 InitiateUploadNewFileRequest* request = | |
625 new InitiateUploadNewFileRequest(sender_.get(), | |
626 url_generator_, | |
627 content_type, | |
628 content_length, | |
629 parent_resource_id, | |
630 title, | |
631 callback); | |
632 request->set_modified_date(options.modified_date); | |
633 request->set_last_viewed_by_me_date(options.last_viewed_by_me_date); | |
634 request->set_properties(options.properties); | |
635 return sender_->StartRequestWithRetry(request); | |
636 } | |
637 | |
638 CancelCallback DriveAPIService::InitiateUploadExistingFile( | |
639 const std::string& content_type, | |
640 int64 content_length, | |
641 const std::string& resource_id, | |
642 const UploadExistingFileOptions& options, | |
643 const InitiateUploadCallback& callback) { | |
644 DCHECK(thread_checker_.CalledOnValidThread()); | |
645 DCHECK(!callback.is_null()); | |
646 | |
647 InitiateUploadExistingFileRequest* request = | |
648 new InitiateUploadExistingFileRequest(sender_.get(), | |
649 url_generator_, | |
650 content_type, | |
651 content_length, | |
652 resource_id, | |
653 options.etag, | |
654 callback); | |
655 request->set_parent_resource_id(options.parent_resource_id); | |
656 request->set_title(options.title); | |
657 request->set_modified_date(options.modified_date); | |
658 request->set_last_viewed_by_me_date(options.last_viewed_by_me_date); | |
659 request->set_properties(options.properties); | |
660 return sender_->StartRequestWithRetry(request); | |
661 } | |
662 | |
663 CancelCallback DriveAPIService::ResumeUpload( | |
664 const GURL& upload_url, | |
665 int64 start_position, | |
666 int64 end_position, | |
667 int64 content_length, | |
668 const std::string& content_type, | |
669 const base::FilePath& local_file_path, | |
670 const UploadRangeCallback& callback, | |
671 const ProgressCallback& progress_callback) { | |
672 DCHECK(thread_checker_.CalledOnValidThread()); | |
673 DCHECK(!callback.is_null()); | |
674 | |
675 return sender_->StartRequestWithRetry( | |
676 new ResumeUploadRequest( | |
677 sender_.get(), | |
678 upload_url, | |
679 start_position, | |
680 end_position, | |
681 content_length, | |
682 content_type, | |
683 local_file_path, | |
684 callback, | |
685 progress_callback)); | |
686 } | |
687 | |
688 CancelCallback DriveAPIService::GetUploadStatus( | |
689 const GURL& upload_url, | |
690 int64 content_length, | |
691 const UploadRangeCallback& callback) { | |
692 DCHECK(thread_checker_.CalledOnValidThread()); | |
693 DCHECK(!callback.is_null()); | |
694 | |
695 return sender_->StartRequestWithRetry(new GetUploadStatusRequest( | |
696 sender_.get(), | |
697 upload_url, | |
698 content_length, | |
699 callback)); | |
700 } | |
701 | |
702 CancelCallback DriveAPIService::MultipartUploadNewFile( | |
703 const std::string& content_type, | |
704 int64 content_length, | |
705 const std::string& parent_resource_id, | |
706 const std::string& title, | |
707 const base::FilePath& local_file_path, | |
708 const drive::UploadNewFileOptions& options, | |
709 const FileResourceCallback& callback, | |
710 const google_apis::ProgressCallback& progress_callback) { | |
711 DCHECK(thread_checker_.CalledOnValidThread()); | |
712 DCHECK(!callback.is_null()); | |
713 | |
714 return sender_->StartRequestWithRetry( | |
715 new google_apis::drive::SingleBatchableDelegateRequest( | |
716 sender_.get(), | |
717 new google_apis::drive::MultipartUploadNewFileDelegate( | |
718 sender_.get(), title, parent_resource_id, content_type, | |
719 content_length, options.modified_date, | |
720 options.last_viewed_by_me_date, local_file_path, | |
721 options.properties, url_generator_, callback, | |
722 progress_callback))); | |
723 } | |
724 | |
725 CancelCallback DriveAPIService::MultipartUploadExistingFile( | |
726 const std::string& content_type, | |
727 int64 content_length, | |
728 const std::string& resource_id, | |
729 const base::FilePath& local_file_path, | |
730 const drive::UploadExistingFileOptions& options, | |
731 const FileResourceCallback& callback, | |
732 const google_apis::ProgressCallback& progress_callback) { | |
733 DCHECK(thread_checker_.CalledOnValidThread()); | |
734 DCHECK(!callback.is_null()); | |
735 | |
736 return sender_->StartRequestWithRetry( | |
737 new google_apis::drive::SingleBatchableDelegateRequest( | |
738 sender_.get(), | |
739 new google_apis::drive::MultipartUploadExistingFileDelegate( | |
740 sender_.get(), options.title, resource_id, | |
741 options.parent_resource_id, content_type, content_length, | |
742 options.modified_date, options.last_viewed_by_me_date, | |
743 local_file_path, options.etag, options.properties, url_generator_, | |
744 callback, progress_callback))); | |
745 } | |
746 | |
747 CancelCallback DriveAPIService::AuthorizeApp( | |
748 const std::string& resource_id, | |
749 const std::string& app_id, | |
750 const AuthorizeAppCallback& callback) { | |
751 DCHECK(thread_checker_.CalledOnValidThread()); | |
752 DCHECK(!callback.is_null()); | |
753 | |
754 // Files.Authorize is only available for whitelisted clients like official | |
755 // Google Chrome. In other cases, we fall back to Files.Get that returns the | |
756 // same value as Files.Authorize without doing authorization. In that case, | |
757 // the app can open if it was authorized by other means (from whitelisted | |
758 // clients or drive.google.com web UI.) | |
759 if (google_apis::IsGoogleChromeAPIKeyUsed()) { | |
760 google_apis::drive::FilesAuthorizeRequest* request = | |
761 new google_apis::drive::FilesAuthorizeRequest( | |
762 sender_.get(), url_generator_, | |
763 base::Bind(&ExtractOpenUrlAndRun, app_id, callback)); | |
764 request->set_app_id(app_id); | |
765 request->set_file_id(resource_id); | |
766 request->set_fields(kFileResourceOpenWithLinksFields); | |
767 return sender_->StartRequestWithRetry(request); | |
768 } else { | |
769 FilesGetRequest* request = new FilesGetRequest( | |
770 sender_.get(), url_generator_, google_apis::IsGoogleChromeAPIKeyUsed(), | |
771 base::Bind(&ExtractOpenUrlAndRun, app_id, callback)); | |
772 request->set_file_id(resource_id); | |
773 request->set_fields(kFileResourceOpenWithLinksFields); | |
774 return sender_->StartRequestWithRetry(request); | |
775 } | |
776 } | |
777 | |
778 CancelCallback DriveAPIService::UninstallApp( | |
779 const std::string& app_id, | |
780 const google_apis::EntryActionCallback& callback) { | |
781 DCHECK(thread_checker_.CalledOnValidThread()); | |
782 DCHECK(!callback.is_null()); | |
783 | |
784 google_apis::drive::AppsDeleteRequest* request = | |
785 new google_apis::drive::AppsDeleteRequest(sender_.get(), url_generator_, | |
786 callback); | |
787 request->set_app_id(app_id); | |
788 return sender_->StartRequestWithRetry(request); | |
789 } | |
790 | |
791 google_apis::CancelCallback DriveAPIService::AddPermission( | |
792 const std::string& resource_id, | |
793 const std::string& email, | |
794 google_apis::drive::PermissionRole role, | |
795 const google_apis::EntryActionCallback& callback) { | |
796 DCHECK(thread_checker_.CalledOnValidThread()); | |
797 DCHECK(!callback.is_null()); | |
798 | |
799 google_apis::drive::PermissionsInsertRequest* request = | |
800 new google_apis::drive::PermissionsInsertRequest(sender_.get(), | |
801 url_generator_, | |
802 callback); | |
803 request->set_id(resource_id); | |
804 request->set_role(role); | |
805 request->set_type(google_apis::drive::PERMISSION_TYPE_USER); | |
806 request->set_value(email); | |
807 return sender_->StartRequestWithRetry(request); | |
808 } | |
809 | |
810 bool DriveAPIService::HasAccessToken() const { | |
811 DCHECK(thread_checker_.CalledOnValidThread()); | |
812 return sender_->auth_service()->HasAccessToken(); | |
813 } | |
814 | |
815 void DriveAPIService::RequestAccessToken(const AuthStatusCallback& callback) { | |
816 DCHECK(thread_checker_.CalledOnValidThread()); | |
817 DCHECK(!callback.is_null()); | |
818 | |
819 const std::string access_token = sender_->auth_service()->access_token(); | |
820 if (!access_token.empty()) { | |
821 callback.Run(google_apis::HTTP_NOT_MODIFIED, access_token); | |
822 return; | |
823 } | |
824 | |
825 // Retrieve the new auth token. | |
826 sender_->auth_service()->StartAuthentication(callback); | |
827 } | |
828 | |
829 bool DriveAPIService::HasRefreshToken() const { | |
830 DCHECK(thread_checker_.CalledOnValidThread()); | |
831 return sender_->auth_service()->HasRefreshToken(); | |
832 } | |
833 | |
834 void DriveAPIService::ClearAccessToken() { | |
835 DCHECK(thread_checker_.CalledOnValidThread()); | |
836 sender_->auth_service()->ClearAccessToken(); | |
837 } | |
838 | |
839 void DriveAPIService::ClearRefreshToken() { | |
840 DCHECK(thread_checker_.CalledOnValidThread()); | |
841 sender_->auth_service()->ClearRefreshToken(); | |
842 } | |
843 | |
844 void DriveAPIService::OnOAuth2RefreshTokenChanged() { | |
845 DCHECK(thread_checker_.CalledOnValidThread()); | |
846 if (CanSendRequest()) { | |
847 FOR_EACH_OBSERVER( | |
848 DriveServiceObserver, observers_, OnReadyToSendRequests()); | |
849 } else if (!HasRefreshToken()) { | |
850 FOR_EACH_OBSERVER( | |
851 DriveServiceObserver, observers_, OnRefreshTokenInvalid()); | |
852 } | |
853 } | |
854 | |
855 scoped_ptr<BatchRequestConfiguratorInterface> | |
856 DriveAPIService::StartBatchRequest() { | |
857 scoped_ptr<google_apis::drive::BatchUploadRequest> request( | |
858 new google_apis::drive::BatchUploadRequest(sender_.get(), | |
859 url_generator_)); | |
860 const base::WeakPtr<google_apis::drive::BatchUploadRequest> weak_ref = | |
861 request->GetWeakPtrAsBatchUploadRequest(); | |
862 // Have sender_ manage the lifetime of the request. | |
863 // TODO(hirono): Currently we need to pass the ownership of the request to | |
864 // RequestSender before the request is committed because the request has a | |
865 // reference to RequestSender and we should ensure to delete the request when | |
866 // the sender is deleted. Resolve the circulating dependency and fix it. | |
867 const google_apis::CancelCallback callback = | |
868 sender_->StartRequestWithRetry(request.release()); | |
869 return make_scoped_ptr<BatchRequestConfiguratorInterface>( | |
870 new BatchRequestConfigurator(weak_ref, callback)); | |
871 } | |
872 | |
873 } // namespace drive | |
OLD | NEW |