diff options
author | kinaba@chromium.org <kinaba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-21 06:18:07 +0000 |
---|---|---|
committer | kinaba@chromium.org <kinaba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-21 06:18:07 +0000 |
commit | 8b2f77c62453f4256bb216ce97d070e132529993 (patch) | |
tree | 755a358679a91b41f991284df63d95ad603a38a1 | |
parent | d7883a8f350fed782b09067329225b230f876c7e (diff) | |
download | chromium_src-8b2f77c62453f4256bb216ce97d070e132529993.zip chromium_src-8b2f77c62453f4256bb216ce97d070e132529993.tar.gz chromium_src-8b2f77c62453f4256bb216ce97d070e132529993.tar.bz2 |
drive: Implement deletion of shared entries under MyDrive as unparenting.
BUG=293003
Review URL: https://chromiumcodereview.appspot.com/24288005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@224574 0039d316-1c4b-4281-b951-d872f2087c98
3 files changed, 140 insertions, 20 deletions
diff --git a/chrome/browser/chromeos/drive/file_system/remove_operation.cc b/chrome/browser/chromeos/drive/file_system/remove_operation.cc index c1a0c585..ca41f7e 100644 --- a/chrome/browser/chromeos/drive/file_system/remove_operation.cc +++ b/chrome/browser/chromeos/drive/file_system/remove_operation.cc @@ -20,9 +20,14 @@ namespace file_system { namespace { // Checks local metadata state before requesting remote delete. +// |parent_resource_id| is set to the resource ID of the parent directory of +// |path|. If it is a special folder like drive/other, empty string is set. +// |local_id| is set to the local ID of the entry located at |path|. +// |entry| is the resource entry for the |path|. FileError CheckLocalState(internal::ResourceMetadata* metadata, const base::FilePath& path, bool is_recursive, + std::string* parent_resource_id, std::string* local_id, ResourceEntry* entry) { FileError error = metadata->GetIdByPath(path, local_id); @@ -43,14 +48,27 @@ FileError CheckLocalState(internal::ResourceMetadata* metadata, return FILE_ERROR_NOT_EMPTY; } + // Get the resource_id of the parent folder. If it is a special folder that + // does not have the server side ID, returns an empty string (not an error). + if (util::IsSpecialResourceId(entry->parent_local_id())) { + *parent_resource_id = ""; + } else { + ResourceEntry parent_entry; + error = metadata->GetResourceEntryById(entry->parent_local_id(), + &parent_entry); + if (error != FILE_ERROR_OK) + return error; + *parent_resource_id = parent_entry.resource_id(); + } + return FILE_ERROR_OK; } // Updates local metadata and cache state after remote delete. -FileError UpdateLocalState(internal::ResourceMetadata* metadata, - internal::FileCache* cache, - const std::string& local_id, - base::FilePath* changed_directory_path) { +FileError UpdateLocalStateAfterDelete(internal::ResourceMetadata* metadata, + internal::FileCache* cache, + const std::string& local_id, + base::FilePath* changed_directory_path) { *changed_directory_path = metadata->GetFilePath(local_id).DirName(); FileError error = metadata->RemoveEntry(local_id); if (error != FILE_ERROR_OK) @@ -62,6 +80,21 @@ FileError UpdateLocalState(internal::ResourceMetadata* metadata, return FILE_ERROR_OK; } +// Updates local metadata and after remote unparenting. +FileError UpdateLocalStateAfterUnparent( + internal::ResourceMetadata* metadata, + const std::string& local_id, + base::FilePath* changed_directory_path) { + *changed_directory_path = metadata->GetFilePath(local_id).DirName(); + + ResourceEntry entry; + FileError error = metadata->GetResourceEntryById(local_id, &entry); + if (error != FILE_ERROR_OK) + return error; + entry.set_parent_local_id(util::kDriveOtherDirSpecialResourceId); + return metadata->RefreshEntry(local_id, entry); +} + } // namespace RemoveOperation::RemoveOperation( @@ -89,6 +122,7 @@ void RemoveOperation::Remove(const base::FilePath& path, DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(!callback.is_null()); + std::string* parent_resource_id = new std::string; std::string* local_id = new std::string; ResourceEntry* entry = new ResourceEntry; base::PostTaskAndReplyWithResult( @@ -98,17 +132,20 @@ void RemoveOperation::Remove(const base::FilePath& path, metadata_, path, is_recursive, + parent_resource_id, local_id, entry), base::Bind(&RemoveOperation::RemoveAfterCheckLocalState, weak_ptr_factory_.GetWeakPtr(), callback, + base::Owned(parent_resource_id), base::Owned(local_id), base::Owned(entry))); } void RemoveOperation::RemoveAfterCheckLocalState( const FileOperationCallback& callback, + const std::string* parent_resource_id, const std::string* local_id, const ResourceEntry* entry, FileError error) { @@ -120,17 +157,40 @@ void RemoveOperation::RemoveAfterCheckLocalState( return; } - scheduler_->DeleteResource( - entry->resource_id(), - base::Bind(&RemoveOperation::RemoveAfterDeleteResource, - weak_ptr_factory_.GetWeakPtr(), - callback, - *local_id)); + // To match with the behavior of drive.google.com: + // Removal of shared entries under MyDrive is just removing from the parent. + // The entry will stay in shared-with-me (in other words, in "drive/other".) + // + // TODO(kinaba): to be more precise, we might be better to branch by whether + // or not the current account is an owner of the file. The code below is + // written under the assumption that |shared_with_me| coincides with that. + if (entry->shared_with_me() && !parent_resource_id->empty()) { + scheduler_->RemoveResourceFromDirectory( + *parent_resource_id, + entry->resource_id(), + base::Bind(&RemoveOperation::RemoveAfterUpdateRemoteState, + weak_ptr_factory_.GetWeakPtr(), + callback, + base::Bind(&UpdateLocalStateAfterUnparent, + metadata_, + *local_id))); + } else { + // Otherwise try sending the entry to trash. + scheduler_->DeleteResource( + entry->resource_id(), + base::Bind(&RemoveOperation::RemoveAfterUpdateRemoteState, + weak_ptr_factory_.GetWeakPtr(), + callback, + base::Bind(&UpdateLocalStateAfterDelete, + metadata_, + cache_, + *local_id))); + } } -void RemoveOperation::RemoveAfterDeleteResource( +void RemoveOperation::RemoveAfterUpdateRemoteState( const FileOperationCallback& callback, - const std::string& local_id, + const base::Callback<FileError(base::FilePath*)>& local_update_task, google_apis::GDataErrorCode status) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(!callback.is_null()); @@ -145,11 +205,7 @@ void RemoveOperation::RemoveAfterDeleteResource( base::PostTaskAndReplyWithResult( blocking_task_runner_.get(), FROM_HERE, - base::Bind(&UpdateLocalState, - metadata_, - cache_, - local_id, - changed_directory_path), + base::Bind(local_update_task, changed_directory_path), base::Bind(&RemoveOperation::RemoveAfterUpdateLocalState, weak_ptr_factory_.GetWeakPtr(), callback, diff --git a/chrome/browser/chromeos/drive/file_system/remove_operation.h b/chrome/browser/chromeos/drive/file_system/remove_operation.h index 5c606c2..e3468bb 100644 --- a/chrome/browser/chromeos/drive/file_system/remove_operation.h +++ b/chrome/browser/chromeos/drive/file_system/remove_operation.h @@ -55,14 +55,16 @@ class RemoveOperation { private: // Part of Remove(). Called after CheckLocalState() completion. void RemoveAfterCheckLocalState(const FileOperationCallback& callback, + const std::string* parent_resource_id, const std::string* local_id, const ResourceEntry* entry, FileError error); // Part of Remove(). Called after server-side removal is done. - void RemoveAfterDeleteResource(const FileOperationCallback& callback, - const std::string& local_id, - google_apis::GDataErrorCode status); + void RemoveAfterUpdateRemoteState( + const FileOperationCallback& callback, + const base::Callback<FileError(base::FilePath*)>& local_update_task, + google_apis::GDataErrorCode status); // Part of Remove(). Called after UpdateLocalState() completion. void RemoveAfterUpdateLocalState(const FileOperationCallback& callback, diff --git a/chrome/browser/chromeos/drive/file_system/remove_operation_unittest.cc b/chrome/browser/chromeos/drive/file_system/remove_operation_unittest.cc index 84ab831..8916267 100644 --- a/chrome/browser/chromeos/drive/file_system/remove_operation_unittest.cc +++ b/chrome/browser/chromeos/drive/file_system/remove_operation_unittest.cc @@ -40,6 +40,8 @@ TEST_F(RemoveOperationTest, RemoveFile) { // Remove a file in subdirectory. error = FILE_ERROR_FAILED; ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_subdir, &entry)); + const std::string resource_id = entry.resource_id(); + operation.Remove(file_in_subdir, false, // is_recursive google_apis::test_util::CreateCopyResultCallback(&error)); @@ -48,6 +50,17 @@ TEST_F(RemoveOperationTest, RemoveFile) { EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(file_in_subdir, &entry)); + // Verify the file is indeed removed in the server. + google_apis::GDataErrorCode gdata_error = google_apis::GDATA_OTHER_ERROR; + scoped_ptr<google_apis::ResourceEntry> gdata_entry; + fake_service()->GetResourceEntry( + resource_id, + google_apis::test_util::CreateCopyResultCallback(&gdata_error, + &gdata_entry)); + test_util::RunBlockingPoolTask(); + ASSERT_EQ(google_apis::HTTP_SUCCESS, gdata_error); + EXPECT_TRUE(gdata_entry->deleted()); + // Try removing non-existing file. error = FILE_ERROR_FAILED; ASSERT_EQ(FILE_ERROR_NOT_FOUND, @@ -113,5 +126,54 @@ TEST_F(RemoveOperationTest, RemoveDirectory) { GetLocalResourceEntry(file_in_non_empty_dir, &entry)); } +TEST_F(RemoveOperationTest, RemoveShared) { + RemoveOperation operation(blocking_task_runner(), observer(), scheduler(), + metadata(), cache()); + + const base::FilePath kPathInMyDrive(FILE_PATH_LITERAL( + "drive/root/shared.txt")); + const base::FilePath kPathInOther(FILE_PATH_LITERAL( + "drive/other/shared.txt")); + + // Prepare a shared file to the root folder. + google_apis::GDataErrorCode gdata_error = google_apis::GDATA_OTHER_ERROR; + scoped_ptr<google_apis::ResourceEntry> gdata_entry; + fake_service()->AddNewFile( + "text/plain", + "dummy content", + fake_service()->GetRootResourceId(), + kPathInMyDrive.BaseName().AsUTF8Unsafe(), + true, // shared_with_me, + google_apis::test_util::CreateCopyResultCallback(&gdata_error, + &gdata_entry)); + test_util::RunBlockingPoolTask(); + ASSERT_EQ(google_apis::HTTP_CREATED, gdata_error); + CheckForUpdates(); + + // Remove it. Locally, the file should be moved to drive/other. + FileError error = FILE_ERROR_FAILED; + ResourceEntry entry; + operation.Remove(kPathInMyDrive, + false, // is_recursive + google_apis::test_util::CreateCopyResultCallback(&error)); + test_util::RunBlockingPoolTask(); + EXPECT_EQ(FILE_ERROR_OK, error); + EXPECT_EQ(FILE_ERROR_NOT_FOUND, + GetLocalResourceEntry(kPathInMyDrive, &entry)); + EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPathInOther, &entry)); + + // Remotely, the entry should have lost its parent. + gdata_error = google_apis::GDATA_OTHER_ERROR; + const std::string resource_id = gdata_entry->resource_id(); + fake_service()->GetResourceEntry( + resource_id, + google_apis::test_util::CreateCopyResultCallback(&gdata_error, + &gdata_entry)); + test_util::RunBlockingPoolTask(); + ASSERT_EQ(google_apis::HTTP_SUCCESS, gdata_error); + EXPECT_FALSE(gdata_entry->deleted()); // It's not deleted. + EXPECT_FALSE(gdata_entry->GetLinkByType(google_apis::Link::LINK_PARENT)); +} + } // namespace file_system } // namespace drive |