summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkinaba@chromium.org <kinaba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-21 06:18:07 +0000
committerkinaba@chromium.org <kinaba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-21 06:18:07 +0000
commit8b2f77c62453f4256bb216ce97d070e132529993 (patch)
tree755a358679a91b41f991284df63d95ad603a38a1
parentd7883a8f350fed782b09067329225b230f876c7e (diff)
downloadchromium_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
-rw-r--r--chrome/browser/chromeos/drive/file_system/remove_operation.cc90
-rw-r--r--chrome/browser/chromeos/drive/file_system/remove_operation.h8
-rw-r--r--chrome/browser/chromeos/drive/file_system/remove_operation_unittest.cc62
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