Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / drive / sync / remove_performer.cc
1 // Copyright 2013 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/chromeos/drive/sync/remove_performer.h"
6
7 #include "base/sequenced_task_runner.h"
8 #include "chrome/browser/chromeos/drive/drive.pb.h"
9 #include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
10 #include "chrome/browser/chromeos/drive/file_system_util.h"
11 #include "chrome/browser/chromeos/drive/job_scheduler.h"
12 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
13 #include "chrome/browser/chromeos/drive/resource_metadata.h"
14 #include "chrome/browser/chromeos/drive/sync/entry_revert_performer.h"
15 #include "content/public/browser/browser_thread.h"
16
17 using content::BrowserThread;
18
19 namespace drive {
20 namespace internal {
21
22 namespace {
23
24 // Updates local metadata and after remote unparenting.
25 FileError UpdateLocalStateAfterUnparent(ResourceMetadata* metadata,
26                                         const std::string& local_id) {
27   ResourceEntry entry;
28   FileError error = metadata->GetResourceEntryById(local_id, &entry);
29   if (error != FILE_ERROR_OK)
30     return error;
31   entry.set_parent_local_id(util::kDriveOtherDirLocalId);
32   return metadata->RefreshEntry(entry);
33 }
34
35 // Utility function to run ResourceMetadata::RemoveEntry from UI thread.
36 void RemoveEntryOnUIThread(base::SequencedTaskRunner* blocking_task_runner,
37                            ResourceMetadata* metadata,
38                            const std::string& local_id,
39                            const FileOperationCallback& callback) {
40   base::PostTaskAndReplyWithResult(
41       blocking_task_runner,
42       FROM_HERE,
43       base::Bind(&ResourceMetadata::RemoveEntry,
44                  base::Unretained(metadata), local_id),
45       callback);
46 }
47
48 }  // namespace
49
50 RemovePerformer::RemovePerformer(
51     base::SequencedTaskRunner* blocking_task_runner,
52     file_system::OperationObserver* observer,
53     JobScheduler* scheduler,
54     ResourceMetadata* metadata)
55     : blocking_task_runner_(blocking_task_runner),
56       observer_(observer),
57       scheduler_(scheduler),
58       metadata_(metadata),
59       entry_revert_performer_(new EntryRevertPerformer(blocking_task_runner,
60                                                        observer,
61                                                        scheduler,
62                                                        metadata)),
63       weak_ptr_factory_(this) {
64   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
65 }
66
67 RemovePerformer::~RemovePerformer() {
68   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
69 }
70
71 // Returns |entry| corresponding to |local_id|.
72 // Adding to that, removes the entry when it does not exist on the server.
73 FileError TryToRemoveLocally(ResourceMetadata* metadata,
74                              const std::string& local_id,
75                              ResourceEntry* entry) {
76   FileError error = metadata->GetResourceEntryById(local_id, entry);
77   if (error != FILE_ERROR_OK || !entry->resource_id().empty())
78     return error;
79   return metadata->RemoveEntry(local_id);
80 }
81
82 void RemovePerformer::Remove(const std::string& local_id,
83                              const ClientContext& context,
84                              const FileOperationCallback& callback) {
85   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
86   DCHECK(!callback.is_null());
87
88   ResourceEntry* entry = new ResourceEntry;
89   base::PostTaskAndReplyWithResult(
90       blocking_task_runner_.get(),
91       FROM_HERE,
92       base::Bind(&TryToRemoveLocally, metadata_, local_id, entry),
93       base::Bind(&RemovePerformer::RemoveAfterGetResourceEntry,
94                  weak_ptr_factory_.GetWeakPtr(),
95                  context,
96                  callback,
97                  base::Owned(entry)));
98 }
99
100 void RemovePerformer::RemoveAfterGetResourceEntry(
101     const ClientContext& context,
102     const FileOperationCallback& callback,
103     const ResourceEntry* entry,
104     FileError error) {
105   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
106   DCHECK(!callback.is_null());
107
108   if (error != FILE_ERROR_OK || entry->resource_id().empty()) {
109     callback.Run(error);
110     return;
111   }
112
113   // To match with the behavior of drive.google.com:
114   // Removal of shared entries under MyDrive is just removing from the parent.
115   // The entry will stay in shared-with-me (in other words, in "drive/other".)
116   //
117   // TODO(kinaba): to be more precise, we might be better to branch by whether
118   // or not the current account is an owner of the file. The code below is
119   // written under the assumption that |shared_with_me| coincides with that.
120   if (entry->shared_with_me()) {
121     UnparentResource(context, callback, entry->resource_id(),
122                      entry->local_id());
123   } else {
124     // Otherwise try sending the entry to trash.
125     TrashResource(context, callback, entry->resource_id(), entry->local_id());
126   }
127 }
128
129 void RemovePerformer::TrashResource(const ClientContext& context,
130                                     const FileOperationCallback& callback,
131                                     const std::string& resource_id,
132                                     const std::string& local_id) {
133   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
134   DCHECK(!callback.is_null());
135
136   scheduler_->TrashResource(
137       resource_id,
138       context,
139       base::Bind(&RemovePerformer::TrashResourceAfterUpdateRemoteState,
140                  weak_ptr_factory_.GetWeakPtr(), context, callback, local_id));
141 }
142
143 void RemovePerformer::TrashResourceAfterUpdateRemoteState(
144     const ClientContext& context,
145     const FileOperationCallback& callback,
146     const std::string& local_id,
147     google_apis::GDataErrorCode status) {
148   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
149   DCHECK(!callback.is_null());
150
151   if (status == google_apis::HTTP_FORBIDDEN) {
152     // Editing this entry is not allowed, revert local changes.
153     entry_revert_performer_->RevertEntry(local_id, context, callback);
154     observer_->OnDriveSyncError(
155         file_system::DRIVE_SYNC_ERROR_DELETE_WITHOUT_PERMISSION, local_id);
156     return;
157   }
158
159   FileError error = GDataToFileError(status);
160   if (error == FILE_ERROR_NOT_FOUND) {  // Remove local entry when not found.
161     RemoveEntryOnUIThread(blocking_task_runner_.get(), metadata_, local_id,
162                           callback);
163     return;
164   }
165
166   // Now we're done. If the entry is trashed on the server, it'll be also
167   // deleted locally on the next update.
168   callback.Run(error);
169 }
170
171 void RemovePerformer::UnparentResource(const ClientContext& context,
172                                        const FileOperationCallback& callback,
173                                        const std::string& resource_id,
174                                        const std::string& local_id) {
175   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
176   DCHECK(!callback.is_null());
177
178   scheduler_->GetResourceEntry(
179       resource_id,
180       context,
181       base::Bind(&RemovePerformer::UnparentResourceAfterGetResourceEntry,
182                  weak_ptr_factory_.GetWeakPtr(), context, callback, local_id));
183 }
184
185 void RemovePerformer::UnparentResourceAfterGetResourceEntry(
186     const ClientContext& context,
187     const FileOperationCallback& callback,
188     const std::string& local_id,
189     google_apis::GDataErrorCode status,
190     scoped_ptr<google_apis::ResourceEntry> resource_entry) {
191   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
192   DCHECK(!callback.is_null());
193
194   FileError error = GDataToFileError(status);
195   if (error == FILE_ERROR_NOT_FOUND) {  // Remove local entry when not found.
196     RemoveEntryOnUIThread(blocking_task_runner_.get(), metadata_, local_id,
197                           callback);
198     return;
199   }
200
201   if (error != FILE_ERROR_OK) {
202     callback.Run(error);
203     return;
204   }
205
206   ResourceEntry entry;
207   std::string parent_resource_id;
208   if (!ConvertToResourceEntry(*resource_entry, &entry, &parent_resource_id)) {
209     callback.Run(FILE_ERROR_NOT_A_FILE);
210     return;
211   }
212
213   if (!entry.shared_with_me()) {
214     // shared_with_me() has changed on the server.
215     UnparentResourceAfterUpdateRemoteState(callback, local_id,
216                                            google_apis::HTTP_CONFLICT);
217     return;
218   }
219
220   if (parent_resource_id.empty()) {
221     // This entry is unparented already.
222     UnparentResourceAfterUpdateRemoteState(callback, local_id,
223                                            google_apis::HTTP_NO_CONTENT);
224     return;
225   }
226
227   scheduler_->RemoveResourceFromDirectory(
228       parent_resource_id,
229       entry.resource_id(),
230       context,
231       base::Bind(&RemovePerformer::UnparentResourceAfterUpdateRemoteState,
232                  weak_ptr_factory_.GetWeakPtr(), callback, local_id));
233 }
234
235 void RemovePerformer::UnparentResourceAfterUpdateRemoteState(
236     const FileOperationCallback& callback,
237     const std::string& local_id,
238     google_apis::GDataErrorCode status) {
239   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
240   DCHECK(!callback.is_null());
241
242   FileError error = GDataToFileError(status);
243   if (error != FILE_ERROR_OK) {
244     callback.Run(error);
245     return;
246   }
247
248   base::PostTaskAndReplyWithResult(
249       blocking_task_runner_.get(),
250       FROM_HERE,
251       base::Bind(&UpdateLocalStateAfterUnparent, metadata_, local_id),
252       callback);
253 }
254
255 }  // namespace internal
256 }  // namespace drive