drive_api_service.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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 "base/task_runner_util.h" 13#include "base/values.h" 14#include "chrome/browser/drive/drive_api_util.h" 15#include "chrome/browser/google_apis/auth_service.h" 16#include "chrome/browser/google_apis/drive_api_parser.h" 17#include "chrome/browser/google_apis/drive_api_requests.h" 18#include "chrome/browser/google_apis/gdata_errorcode.h" 19#include "chrome/browser/google_apis/gdata_wapi_parser.h" 20#include "chrome/browser/google_apis/gdata_wapi_requests.h" 21#include "chrome/browser/google_apis/request_sender.h" 22#include "content/public/browser/browser_thread.h" 23 24using content::BrowserThread; 25using google_apis::AppList; 26using google_apis::AppListCallback; 27using google_apis::AuthStatusCallback; 28using google_apis::AuthorizeAppCallback; 29using google_apis::CancelCallback; 30using google_apis::ChangeList; 31using google_apis::DownloadActionCallback; 32using google_apis::EntryActionCallback; 33using google_apis::FileList; 34using google_apis::FileResource; 35using google_apis::GDATA_OTHER_ERROR; 36using google_apis::GDATA_PARSE_ERROR; 37using google_apis::GDataErrorCode; 38using google_apis::AboutResourceCallback; 39using google_apis::GetContentCallback; 40using google_apis::GetResourceEntryCallback; 41using google_apis::GetResourceEntryRequest; 42using google_apis::GetResourceListCallback; 43using google_apis::GetResourceListRequest; 44using google_apis::GetShareUrlCallback; 45using google_apis::HTTP_NOT_IMPLEMENTED; 46using google_apis::HTTP_SUCCESS; 47using google_apis::InitiateUploadCallback; 48using google_apis::Link; 49using google_apis::ProgressCallback; 50using google_apis::RequestSender; 51using google_apis::ResourceEntry; 52using google_apis::ResourceList; 53using google_apis::UploadRangeCallback; 54using google_apis::UploadRangeResponse; 55using google_apis::drive::AboutGetRequest; 56using google_apis::drive::AppsListRequest; 57using google_apis::drive::ChangesListRequest; 58using google_apis::drive::ChangesListNextPageRequest; 59using google_apis::drive::ChildrenDeleteRequest; 60using google_apis::drive::ChildrenInsertRequest; 61using google_apis::drive::DownloadFileRequest; 62using google_apis::drive::FilesCopyRequest; 63using google_apis::drive::FilesGetRequest; 64using google_apis::drive::FilesInsertRequest; 65using google_apis::drive::FilesPatchRequest; 66using google_apis::drive::FilesListRequest; 67using google_apis::drive::FilesListNextPageRequest; 68using google_apis::drive::FilesTrashRequest; 69using google_apis::drive::GetUploadStatusRequest; 70using google_apis::drive::InitiateUploadExistingFileRequest; 71using google_apis::drive::InitiateUploadNewFileRequest; 72using google_apis::drive::ResumeUploadRequest; 73 74namespace drive { 75 76namespace { 77 78// OAuth2 scopes for Drive API. 79const char kDriveScope[] = "https://www.googleapis.com/auth/drive"; 80const char kDriveAppsReadonlyScope[] = 81 "https://www.googleapis.com/auth/drive.apps.readonly"; 82 83// Mime type to create a directory. 84const char kFolderMimeType[] = "application/vnd.google-apps.folder"; 85 86// Expected max number of files resources in a http request. 87// Be careful not to use something too small because it might overload the 88// server. Be careful not to use something too large because it takes longer 89// time to fetch the result without UI response. 90const int kMaxNumFilesResourcePerRequest = 500; 91const int kMaxNumFilesResourcePerRequestForSearch = 50; 92 93// For performance, we declare all fields we use. 94const char kAboutResourceFields[] = 95 "kind,quotaBytesTotal,quotaBytesUsed,largestChangeId,rootFolderId"; 96const char kFileResourceFields[] = 97 "kind,id,title,createdDate,sharedWithMeDate,downloadUrl,mimeType," 98 "md5Checksum,fileSize,labels/trashed,etag,parents/parentLink,selfLink," 99 "thumbnailLink,alternateLink,embedLink,modifiedDate,lastViewedByMeDate"; 100const char kFileResourceOpenWithLinksFields[] = 101 "kind,id,openWithLinks/*"; 102const char kFileListFields[] = 103 "kind,items(kind,id,title,createdDate,sharedWithMeDate,downloadUrl," 104 "mimeType,md5Checksum,fileSize,labels/trashed,etag,parents/parentLink," 105 "selfLink,thumbnailLink,alternateLink,embedLink,modifiedDate," 106 "lastViewedByMeDate),nextLink"; 107const char kChangeListFields[] = 108 "kind,items(file(kind,id,title,createdDate,sharedWithMeDate,downloadUrl," 109 "mimeType,md5Checksum,fileSize,labels/trashed,etag,parents/parentLink," 110 "selfLink,thumbnailLink,alternateLink,embedLink,modifiedDate," 111 "lastViewedByMeDate),deleted,id,fileId),nextLink,largestChangeId"; 112 113// Callback invoked when the parsing of resource list is completed, 114// regardless whether it is succeeded or not. 115void DidConvertToResourceListOnBlockingPool( 116 const GetResourceListCallback& callback, 117 scoped_ptr<ResourceList> resource_list) { 118 GDataErrorCode error = resource_list ? HTTP_SUCCESS : GDATA_PARSE_ERROR; 119 callback.Run(error, resource_list.Pass()); 120} 121 122// Converts the FileResource value to ResourceEntry and runs |callback| on the 123// UI thread. 124void ConvertFileEntryToResourceEntryAndRun( 125 const GetResourceEntryCallback& callback, 126 GDataErrorCode error, 127 scoped_ptr<FileResource> value) { 128 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 129 DCHECK(!callback.is_null()); 130 131 if (!value) { 132 callback.Run(error, scoped_ptr<ResourceEntry>()); 133 return; 134 } 135 136 // Converting to ResourceEntry is cheap enough to do on UI thread. 137 scoped_ptr<ResourceEntry> entry = 138 util::ConvertFileResourceToResourceEntry(*value); 139 if (!entry) { 140 callback.Run(GDATA_PARSE_ERROR, scoped_ptr<ResourceEntry>()); 141 return; 142 } 143 144 callback.Run(error, entry.Pass()); 145} 146 147// Thin adapter of ConvertFileListToResourceList. 148scoped_ptr<ResourceList> ConvertFileListToResourceList( 149 scoped_ptr<FileList> file_list) { 150 return util::ConvertFileListToResourceList(*file_list); 151} 152 153// Converts the FileList value to ResourceList on blocking pool and runs 154// |callback| on the UI thread. 155void ConvertFileListToResourceListOnBlockingPoolAndRun( 156 scoped_refptr<base::TaskRunner> blocking_task_runner, 157 const GetResourceListCallback& callback, 158 GDataErrorCode error, 159 scoped_ptr<FileList> value) { 160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 161 DCHECK(!callback.is_null()); 162 163 if (!value) { 164 callback.Run(error, scoped_ptr<ResourceList>()); 165 return; 166 } 167 168 // Convert the value on blocking pool. 169 base::PostTaskAndReplyWithResult( 170 blocking_task_runner.get(), 171 FROM_HERE, 172 base::Bind(&ConvertFileListToResourceList, base::Passed(&value)), 173 base::Bind(&DidConvertToResourceListOnBlockingPool, callback)); 174} 175 176// Thin adapter of ConvertChangeListToResourceList. 177scoped_ptr<ResourceList> ConvertChangeListToResourceList( 178 scoped_ptr<ChangeList> change_list) { 179 return util::ConvertChangeListToResourceList(*change_list); 180} 181 182// Converts the FileList value to ResourceList on blocking pool and runs 183// |callback| on the UI thread. 184void ConvertChangeListToResourceListOnBlockingPoolAndRun( 185 scoped_refptr<base::TaskRunner> blocking_task_runner, 186 const GetResourceListCallback& callback, 187 GDataErrorCode error, 188 scoped_ptr<ChangeList> value) { 189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 190 DCHECK(!callback.is_null()); 191 192 if (!value) { 193 callback.Run(error, scoped_ptr<ResourceList>()); 194 return; 195 } 196 197 // Convert the value on blocking pool. 198 base::PostTaskAndReplyWithResult( 199 blocking_task_runner.get(), 200 FROM_HERE, 201 base::Bind(&ConvertChangeListToResourceList, base::Passed(&value)), 202 base::Bind(&DidConvertToResourceListOnBlockingPool, callback)); 203} 204 205// Converts the FileResource value to ResourceEntry for upload range request, 206// and runs |callback| on the UI thread. 207void ConvertFileResourceToResourceEntryForUploadRangeAndRun( 208 const UploadRangeCallback& callback, 209 const UploadRangeResponse& response, 210 scoped_ptr<FileResource> value) { 211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 212 DCHECK(!callback.is_null()); 213 214 if (!value) { 215 callback.Run(response, scoped_ptr<ResourceEntry>()); 216 return; 217 } 218 219 // Converting to ResourceEntry is cheap enough to do on UI thread. 220 scoped_ptr<ResourceEntry> entry = 221 util::ConvertFileResourceToResourceEntry(*value); 222 if (!entry) { 223 callback.Run(UploadRangeResponse(GDATA_PARSE_ERROR, 224 response.start_position_received, 225 response.end_position_received), 226 scoped_ptr<ResourceEntry>()); 227 return; 228 } 229 230 callback.Run(response, entry.Pass()); 231} 232 233void ExtractOpenUrlAndRun(const std::string& app_id, 234 const AuthorizeAppCallback& callback, 235 GDataErrorCode error, 236 scoped_ptr<FileResource> value) { 237 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 238 DCHECK(!callback.is_null()); 239 240 if (!value) { 241 callback.Run(error, GURL()); 242 return; 243 } 244 245 const std::vector<FileResource::OpenWithLink>& open_with_links = 246 value->open_with_links(); 247 for (size_t i = 0; i < open_with_links.size(); ++i) { 248 if (open_with_links[i].app_id == app_id) { 249 callback.Run(HTTP_SUCCESS, open_with_links[i].open_url); 250 return; 251 } 252 } 253 254 // Not found. 255 callback.Run(GDATA_OTHER_ERROR, GURL()); 256} 257 258// Ignores the |entry|, and runs the |callback|. 259void EntryActionCallbackAdapter( 260 const EntryActionCallback& callback, 261 GDataErrorCode error, scoped_ptr<FileResource> entry) { 262 callback.Run(error); 263} 264 265// The resource ID for the root directory for Drive API is defined in the spec: 266// https://developers.google.com/drive/folder 267const char kDriveApiRootDirectoryResourceId[] = "root"; 268 269} // namespace 270 271DriveAPIService::DriveAPIService( 272 OAuth2TokenService* oauth2_token_service, 273 net::URLRequestContextGetter* url_request_context_getter, 274 base::TaskRunner* blocking_task_runner, 275 const GURL& base_url, 276 const GURL& base_download_url, 277 const GURL& wapi_base_url, 278 const std::string& custom_user_agent) 279 : oauth2_token_service_(oauth2_token_service), 280 url_request_context_getter_(url_request_context_getter), 281 blocking_task_runner_(blocking_task_runner), 282 url_generator_(base_url, base_download_url), 283 wapi_url_generator_(wapi_base_url, base_download_url), 284 custom_user_agent_(custom_user_agent) { 285 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 286} 287 288DriveAPIService::~DriveAPIService() { 289 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 290 if (sender_.get()) 291 sender_->auth_service()->RemoveObserver(this); 292} 293 294void DriveAPIService::Initialize(const std::string& account_id) { 295 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 296 297 std::vector<std::string> scopes; 298 scopes.push_back(kDriveScope); 299 scopes.push_back(kDriveAppsReadonlyScope); 300 301 // GData WAPI token. These are for GetShareUrl(). 302 scopes.push_back(util::kDocsListScope); 303 scopes.push_back(util::kDriveAppsScope); 304 305 sender_.reset(new RequestSender( 306 new google_apis::AuthService(oauth2_token_service_, 307 account_id, 308 url_request_context_getter_, 309 scopes), 310 url_request_context_getter_, 311 blocking_task_runner_.get(), 312 custom_user_agent_)); 313 sender_->auth_service()->AddObserver(this); 314} 315 316void DriveAPIService::AddObserver(DriveServiceObserver* observer) { 317 observers_.AddObserver(observer); 318} 319 320void DriveAPIService::RemoveObserver(DriveServiceObserver* observer) { 321 observers_.RemoveObserver(observer); 322} 323 324bool DriveAPIService::CanSendRequest() const { 325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 326 327 return HasRefreshToken(); 328} 329 330ResourceIdCanonicalizer DriveAPIService::GetResourceIdCanonicalizer() const { 331 return base::Bind(&drive::util::CanonicalizeResourceId); 332} 333 334std::string DriveAPIService::GetRootResourceId() const { 335 return kDriveApiRootDirectoryResourceId; 336} 337 338CancelCallback DriveAPIService::GetAllResourceList( 339 const GetResourceListCallback& callback) { 340 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 341 DCHECK(!callback.is_null()); 342 343 FilesListRequest* request = new FilesListRequest( 344 sender_.get(), url_generator_, 345 base::Bind(&ConvertFileListToResourceListOnBlockingPoolAndRun, 346 blocking_task_runner_, callback)); 347 request->set_max_results(kMaxNumFilesResourcePerRequest); 348 request->set_q("trashed = false"); // Exclude trashed files. 349 request->set_fields(kFileListFields); 350 return sender_->StartRequestWithRetry(request); 351} 352 353CancelCallback DriveAPIService::GetResourceListInDirectory( 354 const std::string& directory_resource_id, 355 const GetResourceListCallback& callback) { 356 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 357 DCHECK(!directory_resource_id.empty()); 358 DCHECK(!callback.is_null()); 359 360 // Because children.list method on Drive API v2 returns only the list of 361 // children's references, but we need all file resource list. 362 // So, here we use files.list method instead, with setting parents query. 363 // After the migration from GData WAPI to Drive API v2, we should clean the 364 // code up by moving the responsibility to include "parents" in the query 365 // to client side. 366 // We aren't interested in files in trash in this context, neither. 367 FilesListRequest* request = new FilesListRequest( 368 sender_.get(), url_generator_, 369 base::Bind(&ConvertFileListToResourceListOnBlockingPoolAndRun, 370 blocking_task_runner_, callback)); 371 request->set_max_results(kMaxNumFilesResourcePerRequest); 372 request->set_q(base::StringPrintf( 373 "'%s' in parents and trashed = false", 374 drive::util::EscapeQueryStringValue(directory_resource_id).c_str())); 375 request->set_fields(kFileListFields); 376 return sender_->StartRequestWithRetry(request); 377} 378 379CancelCallback DriveAPIService::Search( 380 const std::string& search_query, 381 const GetResourceListCallback& callback) { 382 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 383 DCHECK(!search_query.empty()); 384 DCHECK(!callback.is_null()); 385 386 FilesListRequest* request = new FilesListRequest( 387 sender_.get(), url_generator_, 388 base::Bind(&ConvertFileListToResourceListOnBlockingPoolAndRun, 389 blocking_task_runner_, callback)); 390 request->set_max_results(kMaxNumFilesResourcePerRequestForSearch); 391 request->set_q(drive::util::TranslateQuery(search_query)); 392 request->set_fields(kFileListFields); 393 return sender_->StartRequestWithRetry(request); 394} 395 396CancelCallback DriveAPIService::SearchByTitle( 397 const std::string& title, 398 const std::string& directory_resource_id, 399 const GetResourceListCallback& callback) { 400 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 401 DCHECK(!title.empty()); 402 DCHECK(!callback.is_null()); 403 404 std::string query; 405 base::StringAppendF(&query, "title = '%s'", 406 drive::util::EscapeQueryStringValue(title).c_str()); 407 if (!directory_resource_id.empty()) { 408 base::StringAppendF( 409 &query, " and '%s' in parents", 410 drive::util::EscapeQueryStringValue(directory_resource_id).c_str()); 411 } 412 query += " and trashed = false"; 413 414 FilesListRequest* request = new FilesListRequest( 415 sender_.get(), url_generator_, 416 base::Bind(&ConvertFileListToResourceListOnBlockingPoolAndRun, 417 blocking_task_runner_, callback)); 418 request->set_max_results(kMaxNumFilesResourcePerRequest); 419 request->set_q(query); 420 request->set_fields(kFileListFields); 421 return sender_->StartRequestWithRetry(request); 422} 423 424CancelCallback DriveAPIService::GetChangeList( 425 int64 start_changestamp, 426 const GetResourceListCallback& callback) { 427 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 428 DCHECK(!callback.is_null()); 429 430 ChangesListRequest* request = new ChangesListRequest( 431 sender_.get(), url_generator_, 432 base::Bind(&ConvertChangeListToResourceListOnBlockingPoolAndRun, 433 blocking_task_runner_, callback)); 434 request->set_max_results(kMaxNumFilesResourcePerRequest); 435 request->set_start_change_id(start_changestamp); 436 request->set_fields(kChangeListFields); 437 return sender_->StartRequestWithRetry(request); 438} 439 440CancelCallback DriveAPIService::GetRemainingChangeList( 441 const GURL& next_link, 442 const GetResourceListCallback& callback) { 443 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 444 DCHECK(!next_link.is_empty()); 445 DCHECK(!callback.is_null()); 446 447 ChangesListNextPageRequest* request = new ChangesListNextPageRequest( 448 sender_.get(), 449 base::Bind(&ConvertChangeListToResourceListOnBlockingPoolAndRun, 450 blocking_task_runner_, callback)); 451 request->set_next_link(next_link); 452 request->set_fields(kChangeListFields); 453 return sender_->StartRequestWithRetry(request); 454} 455 456CancelCallback DriveAPIService::GetRemainingFileList( 457 const GURL& next_link, 458 const GetResourceListCallback& callback) { 459 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 460 DCHECK(!next_link.is_empty()); 461 DCHECK(!callback.is_null()); 462 463 FilesListNextPageRequest* request = new FilesListNextPageRequest( 464 sender_.get(), 465 base::Bind(&ConvertFileListToResourceListOnBlockingPoolAndRun, 466 blocking_task_runner_, callback)); 467 request->set_next_link(next_link); 468 request->set_fields(kFileListFields); 469 return sender_->StartRequestWithRetry(request); 470} 471 472CancelCallback DriveAPIService::GetResourceEntry( 473 const std::string& resource_id, 474 const GetResourceEntryCallback& callback) { 475 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 476 DCHECK(!callback.is_null()); 477 478 FilesGetRequest* request = new FilesGetRequest( 479 sender_.get(), url_generator_, 480 base::Bind(&ConvertFileEntryToResourceEntryAndRun, callback)); 481 request->set_file_id(resource_id); 482 request->set_fields(kFileResourceFields); 483 return sender_->StartRequestWithRetry(request); 484} 485 486CancelCallback DriveAPIService::GetShareUrl( 487 const std::string& resource_id, 488 const GURL& embed_origin, 489 const GetShareUrlCallback& callback) { 490 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 491 DCHECK(!callback.is_null()); 492 493 // Unfortunately "share url" is not yet supported on Drive API v2. 494 // So, as a fallback, we use GData WAPI protocol for this method. 495 // TODO(hidehiko): Get rid of this implementation when share url is 496 // supported on Drive API v2. 497 return sender_->StartRequestWithRetry( 498 new GetResourceEntryRequest(sender_.get(), 499 wapi_url_generator_, 500 resource_id, 501 embed_origin, 502 base::Bind(&util::ParseShareUrlAndRun, 503 callback))); 504} 505 506CancelCallback DriveAPIService::GetAboutResource( 507 const AboutResourceCallback& callback) { 508 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 509 DCHECK(!callback.is_null()); 510 511 AboutGetRequest* request = 512 new AboutGetRequest(sender_.get(), url_generator_, callback); 513 request->set_fields(kAboutResourceFields); 514 return sender_->StartRequestWithRetry(request); 515} 516 517CancelCallback DriveAPIService::GetAppList(const AppListCallback& callback) { 518 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 519 DCHECK(!callback.is_null()); 520 521 return sender_->StartRequestWithRetry( 522 new AppsListRequest(sender_.get(), url_generator_, callback)); 523} 524 525CancelCallback DriveAPIService::DownloadFile( 526 const base::FilePath& local_cache_path, 527 const std::string& resource_id, 528 const DownloadActionCallback& download_action_callback, 529 const GetContentCallback& get_content_callback, 530 const ProgressCallback& progress_callback) { 531 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 532 DCHECK(!download_action_callback.is_null()); 533 // get_content_callback may be null. 534 535 return sender_->StartRequestWithRetry( 536 new DownloadFileRequest(sender_.get(), 537 url_generator_, 538 resource_id, 539 local_cache_path, 540 download_action_callback, 541 get_content_callback, 542 progress_callback)); 543} 544 545CancelCallback DriveAPIService::DeleteResource( 546 const std::string& resource_id, 547 const std::string& etag, 548 const EntryActionCallback& callback) { 549 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 550 DCHECK(!callback.is_null()); 551 552 FilesTrashRequest* request = new FilesTrashRequest( 553 sender_.get(), url_generator_, 554 base::Bind(&EntryActionCallbackAdapter, callback)); 555 request->set_file_id(resource_id); 556 request->set_fields(kFileResourceFields); 557 return sender_->StartRequestWithRetry(request); 558} 559 560CancelCallback DriveAPIService::AddNewDirectory( 561 const std::string& parent_resource_id, 562 const std::string& directory_title, 563 const GetResourceEntryCallback& callback) { 564 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 565 DCHECK(!callback.is_null()); 566 567 FilesInsertRequest* request = new FilesInsertRequest( 568 sender_.get(), url_generator_, 569 base::Bind(&ConvertFileEntryToResourceEntryAndRun, callback)); 570 request->set_mime_type(kFolderMimeType); 571 request->add_parent(parent_resource_id); 572 request->set_title(directory_title); 573 request->set_fields(kFileResourceFields); 574 return sender_->StartRequestWithRetry(request); 575} 576 577CancelCallback DriveAPIService::CopyResource( 578 const std::string& resource_id, 579 const std::string& parent_resource_id, 580 const std::string& new_title, 581 const base::Time& last_modified, 582 const GetResourceEntryCallback& callback) { 583 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 584 DCHECK(!callback.is_null()); 585 586 FilesCopyRequest* request = new FilesCopyRequest( 587 sender_.get(), url_generator_, 588 base::Bind(&ConvertFileEntryToResourceEntryAndRun, callback)); 589 request->set_file_id(resource_id); 590 request->add_parent(parent_resource_id); 591 request->set_title(new_title); 592 request->set_modified_date(last_modified); 593 request->set_fields(kFileResourceFields); 594 return sender_->StartRequestWithRetry(request); 595} 596 597CancelCallback DriveAPIService::CopyHostedDocument( 598 const std::string& resource_id, 599 const std::string& new_title, 600 const GetResourceEntryCallback& callback) { 601 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 602 DCHECK(!callback.is_null()); 603 604 FilesCopyRequest* request = new FilesCopyRequest( 605 sender_.get(), url_generator_, 606 base::Bind(&ConvertFileEntryToResourceEntryAndRun, callback)); 607 request->set_file_id(resource_id); 608 request->set_title(new_title); 609 request->set_fields(kFileResourceFields); 610 return sender_->StartRequestWithRetry(request); 611} 612 613CancelCallback DriveAPIService::MoveResource( 614 const std::string& resource_id, 615 const std::string& parent_resource_id, 616 const std::string& new_title, 617 const base::Time& last_modified, 618 const GetResourceEntryCallback& callback) { 619 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 620 DCHECK(!callback.is_null()); 621 622 FilesPatchRequest* request = new FilesPatchRequest( 623 sender_.get(), url_generator_, 624 base::Bind(&ConvertFileEntryToResourceEntryAndRun, callback)); 625 request->set_file_id(resource_id); 626 request->set_title(new_title); 627 if (!parent_resource_id.empty()) 628 request->add_parent(parent_resource_id); 629 if (!last_modified.is_null()) { 630 request->set_set_modified_date(true); 631 request->set_modified_date(last_modified); 632 } 633 request->set_fields(kFileResourceFields); 634 return sender_->StartRequestWithRetry(request); 635} 636 637CancelCallback DriveAPIService::RenameResource( 638 const std::string& resource_id, 639 const std::string& new_title, 640 const EntryActionCallback& callback) { 641 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 642 DCHECK(!callback.is_null()); 643 644 FilesPatchRequest* request = new FilesPatchRequest( 645 sender_.get(), url_generator_, 646 base::Bind(&EntryActionCallbackAdapter, callback)); 647 request->set_file_id(resource_id); 648 request->set_title(new_title); 649 request->set_fields(kFileResourceFields); 650 return sender_->StartRequestWithRetry(request); 651} 652 653CancelCallback DriveAPIService::TouchResource( 654 const std::string& resource_id, 655 const base::Time& modified_date, 656 const base::Time& last_viewed_by_me_date, 657 const GetResourceEntryCallback& callback) { 658 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 659 DCHECK(!modified_date.is_null()); 660 DCHECK(!last_viewed_by_me_date.is_null()); 661 DCHECK(!callback.is_null()); 662 663 FilesPatchRequest* request = new FilesPatchRequest( 664 sender_.get(), url_generator_, 665 base::Bind(&ConvertFileEntryToResourceEntryAndRun, callback)); 666 // Need to set setModifiedDate to true to overwrite modifiedDate. 667 request->set_set_modified_date(true); 668 669 // Need to set updateViewedDate to false, otherwise the lastViewedByMeDate 670 // will be set to the request time (not the specified time via request). 671 request->set_update_viewed_date(false); 672 673 request->set_modified_date(modified_date); 674 request->set_last_viewed_by_me_date(last_viewed_by_me_date); 675 request->set_fields(kFileResourceFields); 676 return sender_->StartRequestWithRetry(request); 677} 678 679CancelCallback DriveAPIService::AddResourceToDirectory( 680 const std::string& parent_resource_id, 681 const std::string& resource_id, 682 const EntryActionCallback& callback) { 683 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 684 DCHECK(!callback.is_null()); 685 686 ChildrenInsertRequest* request = 687 new ChildrenInsertRequest(sender_.get(), url_generator_, callback); 688 request->set_folder_id(parent_resource_id); 689 request->set_id(resource_id); 690 return sender_->StartRequestWithRetry(request); 691} 692 693CancelCallback DriveAPIService::RemoveResourceFromDirectory( 694 const std::string& parent_resource_id, 695 const std::string& resource_id, 696 const EntryActionCallback& callback) { 697 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 698 DCHECK(!callback.is_null()); 699 700 ChildrenDeleteRequest* request = 701 new ChildrenDeleteRequest(sender_.get(), url_generator_, callback); 702 request->set_child_id(resource_id); 703 request->set_folder_id(parent_resource_id); 704 return sender_->StartRequestWithRetry(request); 705} 706 707CancelCallback DriveAPIService::InitiateUploadNewFile( 708 const std::string& content_type, 709 int64 content_length, 710 const std::string& parent_resource_id, 711 const std::string& title, 712 const InitiateUploadCallback& callback) { 713 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 714 DCHECK(!callback.is_null()); 715 716 return sender_->StartRequestWithRetry( 717 new InitiateUploadNewFileRequest( 718 sender_.get(), 719 url_generator_, 720 content_type, 721 content_length, 722 parent_resource_id, 723 title, 724 callback)); 725} 726 727CancelCallback DriveAPIService::InitiateUploadExistingFile( 728 const std::string& content_type, 729 int64 content_length, 730 const std::string& resource_id, 731 const std::string& etag, 732 const InitiateUploadCallback& callback) { 733 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 734 DCHECK(!callback.is_null()); 735 736 return sender_->StartRequestWithRetry( 737 new InitiateUploadExistingFileRequest( 738 sender_.get(), 739 url_generator_, 740 content_type, 741 content_length, 742 resource_id, 743 etag, 744 callback)); 745} 746 747CancelCallback DriveAPIService::ResumeUpload( 748 const GURL& upload_url, 749 int64 start_position, 750 int64 end_position, 751 int64 content_length, 752 const std::string& content_type, 753 const base::FilePath& local_file_path, 754 const UploadRangeCallback& callback, 755 const ProgressCallback& progress_callback) { 756 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 757 DCHECK(!callback.is_null()); 758 759 return sender_->StartRequestWithRetry( 760 new ResumeUploadRequest( 761 sender_.get(), 762 upload_url, 763 start_position, 764 end_position, 765 content_length, 766 content_type, 767 local_file_path, 768 base::Bind(&ConvertFileResourceToResourceEntryForUploadRangeAndRun, 769 callback), 770 progress_callback)); 771} 772 773CancelCallback DriveAPIService::GetUploadStatus( 774 const GURL& upload_url, 775 int64 content_length, 776 const UploadRangeCallback& callback) { 777 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 778 DCHECK(!callback.is_null()); 779 780 return sender_->StartRequestWithRetry(new GetUploadStatusRequest( 781 sender_.get(), 782 upload_url, 783 content_length, 784 base::Bind(&ConvertFileResourceToResourceEntryForUploadRangeAndRun, 785 callback))); 786} 787 788CancelCallback DriveAPIService::AuthorizeApp( 789 const std::string& resource_id, 790 const std::string& app_id, 791 const AuthorizeAppCallback& callback) { 792 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 793 DCHECK(!callback.is_null()); 794 795 FilesGetRequest* request = new FilesGetRequest( 796 sender_.get(), url_generator_, 797 base::Bind(&ExtractOpenUrlAndRun, app_id, callback)); 798 request->set_file_id(resource_id); 799 request->set_fields(kFileResourceOpenWithLinksFields); 800 return sender_->StartRequestWithRetry(request); 801} 802 803CancelCallback DriveAPIService::GetResourceListInDirectoryByWapi( 804 const std::string& directory_resource_id, 805 const google_apis::GetResourceListCallback& callback) { 806 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 807 DCHECK(!directory_resource_id.empty()); 808 DCHECK(!callback.is_null()); 809 810 return sender_->StartRequestWithRetry( 811 new GetResourceListRequest(sender_.get(), 812 wapi_url_generator_, 813 GURL(), // No override url 814 0, // start changestamp 815 std::string(), // empty search query 816 directory_resource_id, 817 callback)); 818} 819 820CancelCallback DriveAPIService::GetRemainingResourceList( 821 const GURL& next_link, 822 const google_apis::GetResourceListCallback& callback) { 823 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 824 DCHECK(!next_link.is_empty()); 825 DCHECK(!callback.is_null()); 826 827 return sender_->StartRequestWithRetry( 828 new GetResourceListRequest(sender_.get(), 829 wapi_url_generator_, 830 next_link, 831 0, // start changestamp 832 std::string(), // empty search query 833 std::string(), // no directory resource id 834 callback)); 835} 836 837bool DriveAPIService::HasAccessToken() const { 838 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 839 return sender_->auth_service()->HasAccessToken(); 840} 841 842void DriveAPIService::RequestAccessToken(const AuthStatusCallback& callback) { 843 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 844 DCHECK(!callback.is_null()); 845 846 const std::string access_token = sender_->auth_service()->access_token(); 847 if (!access_token.empty()) { 848 callback.Run(google_apis::HTTP_NOT_MODIFIED, access_token); 849 return; 850 } 851 852 // Retrieve the new auth token. 853 sender_->auth_service()->StartAuthentication(callback); 854} 855 856bool DriveAPIService::HasRefreshToken() const { 857 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 858 return sender_->auth_service()->HasRefreshToken(); 859} 860 861void DriveAPIService::ClearAccessToken() { 862 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 863 sender_->auth_service()->ClearAccessToken(); 864} 865 866void DriveAPIService::ClearRefreshToken() { 867 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 868 sender_->auth_service()->ClearRefreshToken(); 869} 870 871void DriveAPIService::OnOAuth2RefreshTokenChanged() { 872 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 873 if (CanSendRequest()) { 874 FOR_EACH_OBSERVER( 875 DriveServiceObserver, observers_, OnReadyToSendRequests()); 876 } else if (!HasRefreshToken()) { 877 FOR_EACH_OBSERVER( 878 DriveServiceObserver, observers_, OnRefreshTokenInvalid()); 879 } 880} 881 882} // namespace drive 883