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