OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/drive/fake_drive_service.h" | 5 #include "chrome/browser/drive/fake_drive_service.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 16 matching lines...) Expand all Loading... |
27 | 27 |
28 using content::BrowserThread; | 28 using content::BrowserThread; |
29 using google_apis::AboutResource; | 29 using google_apis::AboutResource; |
30 using google_apis::AboutResourceCallback; | 30 using google_apis::AboutResourceCallback; |
31 using google_apis::AccountMetadata; | 31 using google_apis::AccountMetadata; |
32 using google_apis::AppList; | 32 using google_apis::AppList; |
33 using google_apis::AppListCallback; | 33 using google_apis::AppListCallback; |
34 using google_apis::AuthStatusCallback; | 34 using google_apis::AuthStatusCallback; |
35 using google_apis::AuthorizeAppCallback; | 35 using google_apis::AuthorizeAppCallback; |
36 using google_apis::CancelCallback; | 36 using google_apis::CancelCallback; |
| 37 using google_apis::ChangeResource; |
37 using google_apis::DownloadActionCallback; | 38 using google_apis::DownloadActionCallback; |
38 using google_apis::EntryActionCallback; | 39 using google_apis::EntryActionCallback; |
| 40 using google_apis::FileResource; |
39 using google_apis::GDATA_FILE_ERROR; | 41 using google_apis::GDATA_FILE_ERROR; |
40 using google_apis::GDATA_NO_CONNECTION; | 42 using google_apis::GDATA_NO_CONNECTION; |
41 using google_apis::GDATA_OTHER_ERROR; | 43 using google_apis::GDATA_OTHER_ERROR; |
42 using google_apis::GDataErrorCode; | 44 using google_apis::GDataErrorCode; |
43 using google_apis::GetContentCallback; | 45 using google_apis::GetContentCallback; |
44 using google_apis::GetResourceEntryCallback; | 46 using google_apis::GetResourceEntryCallback; |
45 using google_apis::GetResourceListCallback; | 47 using google_apis::GetResourceListCallback; |
46 using google_apis::GetShareUrlCallback; | 48 using google_apis::GetShareUrlCallback; |
47 using google_apis::HTTP_BAD_REQUEST; | 49 using google_apis::HTTP_BAD_REQUEST; |
48 using google_apis::HTTP_CREATED; | 50 using google_apis::HTTP_CREATED; |
49 using google_apis::HTTP_NOT_FOUND; | 51 using google_apis::HTTP_NOT_FOUND; |
50 using google_apis::HTTP_NO_CONTENT; | 52 using google_apis::HTTP_NO_CONTENT; |
51 using google_apis::HTTP_PRECONDITION; | 53 using google_apis::HTTP_PRECONDITION; |
52 using google_apis::HTTP_RESUME_INCOMPLETE; | 54 using google_apis::HTTP_RESUME_INCOMPLETE; |
53 using google_apis::HTTP_SUCCESS; | 55 using google_apis::HTTP_SUCCESS; |
54 using google_apis::InitiateUploadCallback; | 56 using google_apis::InitiateUploadCallback; |
55 using google_apis::Link; | 57 using google_apis::Link; |
| 58 using google_apis::ParentReference; |
56 using google_apis::ProgressCallback; | 59 using google_apis::ProgressCallback; |
57 using google_apis::ResourceEntry; | 60 using google_apis::ResourceEntry; |
58 using google_apis::ResourceList; | 61 using google_apis::ResourceList; |
59 using google_apis::UploadRangeCallback; | 62 using google_apis::UploadRangeCallback; |
60 using google_apis::UploadRangeResponse; | 63 using google_apis::UploadRangeResponse; |
61 namespace test_util = google_apis::test_util; | 64 namespace test_util = google_apis::test_util; |
62 | 65 |
63 namespace drive { | 66 namespace drive { |
64 namespace { | 67 namespace { |
65 | 68 |
66 // Rel property of an upload link in the entries dictionary value. | 69 // Mime type of directories. |
67 const char kUploadUrlRel[] = | 70 const char kDriveFolderMimeType[] = "application/vnd.google-apps.folder"; |
68 "http://schemas.google.com/g/2005#resumable-create-media"; | |
69 | |
70 // Rel property of a share link in the entries dictionary value. | |
71 const char kShareUrlRel[] = | |
72 "http://schemas.google.com/docs/2007#share"; | |
73 | 71 |
74 // Returns true if a resource entry matches with the search query. | 72 // Returns true if a resource entry matches with the search query. |
75 // Supports queries consist of following format. | 73 // Supports queries consist of following format. |
76 // - Phrases quoted by double/single quotes | 74 // - Phrases quoted by double/single quotes |
77 // - AND search for multiple words/phrases segmented by space | 75 // - AND search for multiple words/phrases segmented by space |
78 // - Limited attribute search. Only "title:" is supported. | 76 // - Limited attribute search. Only "title:" is supported. |
79 bool EntryMatchWithQuery(const ResourceEntry& entry, | 77 bool EntryMatchWithQuery(const ResourceEntry& entry, |
80 const std::string& query) { | 78 const std::string& query) { |
81 base::StringTokenizer tokenizer(query, " "); | 79 base::StringTokenizer tokenizer(query, " "); |
82 tokenizer.set_quote_chars("\"'"); | 80 tokenizer.set_quote_chars("\"'"); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
119 end_position), | 117 end_position), |
120 base::Passed(&entry))); | 118 base::Passed(&entry))); |
121 } | 119 } |
122 | 120 |
123 void EntryActionCallbackAdapter( | 121 void EntryActionCallbackAdapter( |
124 const EntryActionCallback& callback, | 122 const EntryActionCallback& callback, |
125 GDataErrorCode error, scoped_ptr<ResourceEntry> resource_entry) { | 123 GDataErrorCode error, scoped_ptr<ResourceEntry> resource_entry) { |
126 callback.Run(error); | 124 callback.Run(error); |
127 } | 125 } |
128 | 126 |
129 void ClearPropatiesForPermanentDelete(base::DictionaryValue* entry) { | |
130 scoped_ptr<base::DictionaryValue> new_entry(new base::DictionaryValue); | |
131 const char* kPreservedProperties[] = { | |
132 "docs$removed", "docs$changestamp", "gd$resourceId", "id", "updated" | |
133 }; | |
134 | |
135 for (size_t i = 0; i < arraysize(kPreservedProperties); ++i) { | |
136 const char* key = kPreservedProperties[i]; | |
137 scoped_ptr<base::Value> value; | |
138 if (entry->Remove(key, &value)) | |
139 new_entry->Set(key, value.release()); | |
140 } | |
141 | |
142 entry->Swap(new_entry.get()); | |
143 } | |
144 | |
145 } // namespace | 127 } // namespace |
146 | 128 |
| 129 struct FakeDriveService::EntryInfo { |
| 130 google_apis::ChangeResource change_resource; |
| 131 GURL share_url; |
| 132 std::string content_data; |
| 133 }; |
| 134 |
147 struct FakeDriveService::UploadSession { | 135 struct FakeDriveService::UploadSession { |
148 std::string content_type; | 136 std::string content_type; |
149 int64 content_length; | 137 int64 content_length; |
150 std::string parent_resource_id; | 138 std::string parent_resource_id; |
151 std::string resource_id; | 139 std::string resource_id; |
152 std::string etag; | 140 std::string etag; |
153 std::string title; | 141 std::string title; |
154 | 142 |
155 int64 uploaded_size; | 143 int64 uploaded_size; |
156 | 144 |
(...skipping 30 matching lines...) Expand all Loading... |
187 about_resource_load_count_(0), | 175 about_resource_load_count_(0), |
188 app_list_load_count_(0), | 176 app_list_load_count_(0), |
189 blocked_resource_list_load_count_(0), | 177 blocked_resource_list_load_count_(0), |
190 offline_(false), | 178 offline_(false), |
191 never_return_all_resource_list_(false) { | 179 never_return_all_resource_list_(false) { |
192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
193 } | 181 } |
194 | 182 |
195 FakeDriveService::~FakeDriveService() { | 183 FakeDriveService::~FakeDriveService() { |
196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 185 STLDeleteValues(&entries_); |
197 } | 186 } |
198 | 187 |
199 bool FakeDriveService::LoadResourceListForWapi( | 188 bool FakeDriveService::LoadResourceListForWapi( |
200 const std::string& relative_path) { | 189 const std::string& relative_path) { |
201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
202 scoped_ptr<base::Value> raw_value = test_util::LoadJSONFile(relative_path); | 191 scoped_ptr<base::Value> raw_value = test_util::LoadJSONFile(relative_path); |
203 base::DictionaryValue* as_dict = NULL; | 192 base::DictionaryValue* as_dict = NULL; |
204 scoped_ptr<base::Value> feed; | 193 scoped_ptr<base::Value> feed; |
205 base::DictionaryValue* feed_as_dict = NULL; | 194 base::DictionaryValue* feed_as_dict = NULL; |
206 | 195 |
207 // Extract the "feed" from the raw value and take the ownership. | 196 // Extract the "feed" from the raw value and take the ownership. |
208 // Note that Remove() transfers the ownership to |feed|. | 197 // Note that Remove() transfers the ownership to |feed|. |
209 if (raw_value->GetAsDictionary(&as_dict) && | 198 if (raw_value->GetAsDictionary(&as_dict) && |
210 as_dict->Remove("feed", &feed) && | 199 as_dict->Remove("feed", &feed) && |
211 feed->GetAsDictionary(&feed_as_dict)) { | 200 feed->GetAsDictionary(&feed_as_dict)) { |
212 ignore_result(feed.release()); | |
213 resource_list_value_.reset(feed_as_dict); | |
214 | |
215 // Go through entries and convert test$data from a string to a binary blob. | |
216 base::ListValue* entries = NULL; | 201 base::ListValue* entries = NULL; |
217 if (feed_as_dict->GetList("entry", &entries)) { | 202 if (feed_as_dict->GetList("entry", &entries)) { |
218 for (size_t i = 0; i < entries->GetSize(); ++i) { | 203 for (size_t i = 0; i < entries->GetSize(); ++i) { |
219 base::DictionaryValue* entry = NULL; | 204 base::DictionaryValue* entry = NULL; |
220 std::string content_data; | 205 if (entries->GetDictionary(i, &entry)) { |
221 if (entries->GetDictionary(i, &entry) && | 206 scoped_ptr<ResourceEntry> resource_entry = |
222 entry->GetString("test$data", &content_data)) { | 207 ResourceEntry::CreateFrom(*entry); |
223 entry->Set("test$data", | 208 |
224 base::BinaryValue::CreateWithCopiedBuffer( | 209 const std::string resource_id = resource_entry->resource_id(); |
225 content_data.c_str(), content_data.size())); | 210 EntryInfoMap::iterator it = entries_.find(resource_id); |
| 211 if (it == entries_.end()) { |
| 212 it = entries_.insert( |
| 213 std::make_pair(resource_id, new EntryInfo)).first; |
| 214 } |
| 215 EntryInfo* new_entry = it->second; |
| 216 |
| 217 ChangeResource* change = &new_entry->change_resource; |
| 218 change->set_change_id(resource_entry->changestamp()); |
| 219 change->set_file_id(resource_id); |
| 220 change->set_file( |
| 221 util::ConvertResourceEntryToFileResource(*resource_entry)); |
| 222 |
| 223 const Link* share_url = |
| 224 resource_entry->GetLinkByType(Link::LINK_SHARE); |
| 225 if (share_url) |
| 226 new_entry->share_url = share_url->href(); |
| 227 |
| 228 entry->GetString("test$data", &new_entry->content_data); |
226 } | 229 } |
227 } | 230 } |
228 } | 231 } |
229 } | 232 } |
230 | 233 |
231 return resource_list_value_; | 234 return feed_as_dict; |
232 } | 235 } |
233 | 236 |
234 bool FakeDriveService::LoadAccountMetadataForWapi( | 237 bool FakeDriveService::LoadAccountMetadataForWapi( |
235 const std::string& relative_path) { | 238 const std::string& relative_path) { |
236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
237 | 240 |
238 // Load JSON data, which must be a dictionary. | 241 // Load JSON data, which must be a dictionary. |
239 scoped_ptr<base::Value> value = test_util::LoadJSONFile(relative_path); | 242 scoped_ptr<base::Value> value = test_util::LoadJSONFile(relative_path); |
240 CHECK_EQ(base::Value::TYPE_DICTIONARY, value->GetType()); | 243 CHECK_EQ(base::Value::TYPE_DICTIONARY, value->GetType()); |
241 account_metadata_value_.reset( | 244 account_metadata_value_.reset( |
242 static_cast<base::DictionaryValue*>(value.release())); | 245 static_cast<base::DictionaryValue*>(value.release())); |
243 | 246 |
244 // Update the largest_changestamp_. | 247 // Update the largest_changestamp_. |
245 scoped_ptr<AccountMetadata> account_metadata = | 248 scoped_ptr<AccountMetadata> account_metadata = |
246 AccountMetadata::CreateFrom(*account_metadata_value_); | 249 AccountMetadata::CreateFrom(*account_metadata_value_); |
247 largest_changestamp_ = account_metadata->largest_changestamp(); | 250 largest_changestamp_ = account_metadata->largest_changestamp(); |
248 | 251 |
249 // Add the largest changestamp to the existing entries. | 252 // Add the largest changestamp to the existing entries. |
250 // This will be used to generate change lists in GetResourceList(). | 253 // This will be used to generate change lists in GetResourceList(). |
251 if (resource_list_value_) { | 254 for (EntryInfoMap::iterator it = entries_.begin(); it != entries_.end(); ++it) |
252 base::ListValue* entries = NULL; | 255 it->second->change_resource.set_change_id(largest_changestamp_); |
253 if (resource_list_value_->GetList("entry", &entries)) { | |
254 for (size_t i = 0; i < entries->GetSize(); ++i) { | |
255 base::DictionaryValue* entry = NULL; | |
256 if (entries->GetDictionary(i, &entry)) { | |
257 entry->SetString("docs$changestamp.value", | |
258 base::Int64ToString(largest_changestamp_)); | |
259 } | |
260 } | |
261 } | |
262 } | |
263 | 256 |
264 return account_metadata_value_; | 257 return account_metadata_value_; |
265 } | 258 } |
266 | 259 |
267 bool FakeDriveService::LoadAppListForDriveApi( | 260 bool FakeDriveService::LoadAppListForDriveApi( |
268 const std::string& relative_path) { | 261 const std::string& relative_path) { |
269 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
270 | 263 |
271 // Load JSON data, which must be a dictionary. | 264 // Load JSON data, which must be a dictionary. |
272 scoped_ptr<base::Value> value = test_util::LoadJSONFile(relative_path); | 265 scoped_ptr<base::Value> value = test_util::LoadJSONFile(relative_path); |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
458 if (offline_) { | 451 if (offline_) { |
459 scoped_ptr<ResourceEntry> null; | 452 scoped_ptr<ResourceEntry> null; |
460 base::MessageLoop::current()->PostTask( | 453 base::MessageLoop::current()->PostTask( |
461 FROM_HERE, | 454 FROM_HERE, |
462 base::Bind(callback, | 455 base::Bind(callback, |
463 GDATA_NO_CONNECTION, | 456 GDATA_NO_CONNECTION, |
464 base::Passed(&null))); | 457 base::Passed(&null))); |
465 return CancelCallback(); | 458 return CancelCallback(); |
466 } | 459 } |
467 | 460 |
468 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); | 461 EntryInfo* entry = FindEntryByResourceId(resource_id); |
469 if (entry) { | 462 if (entry) { |
470 scoped_ptr<ResourceEntry> resource_entry = | 463 scoped_ptr<ResourceEntry> resource_entry = |
471 ResourceEntry::CreateFrom(*entry); | 464 util::ConvertChangeResourceToResourceEntry(entry->change_resource); |
472 base::MessageLoop::current()->PostTask( | 465 base::MessageLoop::current()->PostTask( |
473 FROM_HERE, | 466 FROM_HERE, |
474 base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_entry))); | 467 base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_entry))); |
475 return CancelCallback(); | 468 return CancelCallback(); |
476 } | 469 } |
477 | 470 |
478 scoped_ptr<ResourceEntry> null; | 471 scoped_ptr<ResourceEntry> null; |
479 base::MessageLoop::current()->PostTask( | 472 base::MessageLoop::current()->PostTask( |
480 FROM_HERE, | 473 FROM_HERE, |
481 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); | 474 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); |
(...skipping 10 matching lines...) Expand all Loading... |
492 if (offline_) { | 485 if (offline_) { |
493 scoped_ptr<ResourceEntry> null; | 486 scoped_ptr<ResourceEntry> null; |
494 base::MessageLoop::current()->PostTask( | 487 base::MessageLoop::current()->PostTask( |
495 FROM_HERE, | 488 FROM_HERE, |
496 base::Bind(callback, | 489 base::Bind(callback, |
497 GDATA_NO_CONNECTION, | 490 GDATA_NO_CONNECTION, |
498 GURL())); | 491 GURL())); |
499 return CancelCallback(); | 492 return CancelCallback(); |
500 } | 493 } |
501 | 494 |
502 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); | 495 EntryInfo* entry = FindEntryByResourceId(resource_id); |
503 if (entry) { | 496 if (entry) { |
504 // Share urls are stored in the resource entry, and they do not rely on the | 497 base::MessageLoop::current()->PostTask( |
505 // embedding origin. | 498 FROM_HERE, |
506 scoped_ptr<ResourceEntry> resource_entry = | 499 base::Bind(callback, HTTP_SUCCESS, entry->share_url)); |
507 ResourceEntry::CreateFrom(*entry); | |
508 const Link* share_url = resource_entry->GetLinkByType(Link::LINK_SHARE); | |
509 if (share_url) { | |
510 base::MessageLoop::current()->PostTask( | |
511 FROM_HERE, | |
512 base::Bind(callback, HTTP_SUCCESS, share_url->href())); | |
513 } else { | |
514 base::MessageLoop::current()->PostTask( | |
515 FROM_HERE, | |
516 base::Bind(callback, HTTP_SUCCESS, GURL())); | |
517 } | |
518 return CancelCallback(); | 500 return CancelCallback(); |
519 } | 501 } |
520 | 502 |
521 scoped_ptr<ResourceEntry> null; | |
522 base::MessageLoop::current()->PostTask( | 503 base::MessageLoop::current()->PostTask( |
523 FROM_HERE, | 504 FROM_HERE, |
524 base::Bind(callback, HTTP_NOT_FOUND, GURL())); | 505 base::Bind(callback, HTTP_NOT_FOUND, GURL())); |
525 return CancelCallback(); | 506 return CancelCallback(); |
526 } | 507 } |
527 | 508 |
528 CancelCallback FakeDriveService::GetAboutResource( | 509 CancelCallback FakeDriveService::GetAboutResource( |
529 const AboutResourceCallback& callback) { | 510 const AboutResourceCallback& callback) { |
530 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 511 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
531 DCHECK(!callback.is_null()); | 512 DCHECK(!callback.is_null()); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
582 const EntryActionCallback& callback) { | 563 const EntryActionCallback& callback) { |
583 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 564 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
584 DCHECK(!callback.is_null()); | 565 DCHECK(!callback.is_null()); |
585 | 566 |
586 if (offline_) { | 567 if (offline_) { |
587 base::MessageLoop::current()->PostTask( | 568 base::MessageLoop::current()->PostTask( |
588 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); | 569 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); |
589 return CancelCallback(); | 570 return CancelCallback(); |
590 } | 571 } |
591 | 572 |
592 base::ListValue* entries = NULL; | 573 EntryInfo* entry = FindEntryByResourceId(resource_id); |
593 if (resource_list_value_->GetList("entry", &entries)) { | 574 if (entry) { |
594 for (size_t i = 0; i < entries->GetSize(); ++i) { | 575 ChangeResource* change = &entry->change_resource; |
595 base::DictionaryValue* entry = NULL; | 576 const FileResource* file = change->file(); |
596 std::string current_resource_id; | 577 if (change->is_deleted()) { |
597 if (entries->GetDictionary(i, &entry) && | 578 base::MessageLoop::current()->PostTask( |
598 entry->GetString("gd$resourceId.$t", ¤t_resource_id) && | 579 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); |
599 resource_id == current_resource_id) { | 580 return CancelCallback(); |
600 if (entry->HasKey("docs$removed")) { | 581 } |
601 base::MessageLoop::current()->PostTask( | |
602 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | |
603 return CancelCallback(); | |
604 } | |
605 | 582 |
606 std::string entry_etag; | 583 if (!etag.empty() && etag != file->etag()) { |
607 entry->GetString("gd$etag", &entry_etag); | 584 base::MessageLoop::current()->PostTask( |
608 if (!etag.empty() && entry_etag != etag) { | 585 FROM_HERE, base::Bind(callback, HTTP_PRECONDITION)); |
609 base::MessageLoop::current()->PostTask( | 586 return CancelCallback(); |
610 FROM_HERE, base::Bind(callback, HTTP_PRECONDITION)); | 587 } |
611 return CancelCallback(); | |
612 } | |
613 | 588 |
614 entry->Set("docs$removed", new base::DictionaryValue); | 589 change->set_deleted(true); |
615 AddNewChangestamp(entry); | 590 AddNewChangestamp(change); |
616 ClearPropatiesForPermanentDelete(entry); | 591 change->set_file(scoped_ptr<FileResource>()); |
617 base::MessageLoop::current()->PostTask( | 592 base::MessageLoop::current()->PostTask( |
618 FROM_HERE, base::Bind(callback, HTTP_NO_CONTENT)); | 593 FROM_HERE, base::Bind(callback, HTTP_NO_CONTENT)); |
619 return CancelCallback(); | 594 return CancelCallback(); |
620 } | |
621 } | |
622 } | 595 } |
623 | 596 |
624 base::MessageLoop::current()->PostTask( | 597 base::MessageLoop::current()->PostTask( |
625 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | 598 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); |
626 return CancelCallback(); | 599 return CancelCallback(); |
627 } | 600 } |
628 | 601 |
629 CancelCallback FakeDriveService::TrashResource( | 602 CancelCallback FakeDriveService::TrashResource( |
630 const std::string& resource_id, | 603 const std::string& resource_id, |
631 const EntryActionCallback& callback) { | 604 const EntryActionCallback& callback) { |
632 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 605 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
633 DCHECK(!callback.is_null()); | 606 DCHECK(!callback.is_null()); |
634 | 607 |
635 if (offline_) { | 608 if (offline_) { |
636 base::MessageLoop::current()->PostTask( | 609 base::MessageLoop::current()->PostTask( |
637 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); | 610 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); |
638 return CancelCallback(); | 611 return CancelCallback(); |
639 } | 612 } |
640 | 613 |
641 base::ListValue* entries = NULL; | 614 EntryInfo* entry = FindEntryByResourceId(resource_id); |
642 // Go through entries and remove the one that matches |resource_id|. | 615 if (entry) { |
643 if (resource_list_value_->GetList("entry", &entries)) { | 616 ChangeResource* change = &entry->change_resource; |
644 for (size_t i = 0; i < entries->GetSize(); ++i) { | 617 FileResource* file = change->mutable_file(); |
645 base::DictionaryValue* entry = NULL; | 618 GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; |
646 std::string current_resource_id; | 619 if (change->is_deleted() || file->labels().is_trashed()) { |
647 if (entries->GetDictionary(i, &entry) && | 620 error = HTTP_NOT_FOUND; |
648 entry->GetString("gd$resourceId.$t", ¤t_resource_id) && | 621 } else { |
649 resource_id == current_resource_id) { | 622 file->mutable_labels()->set_trashed(true); |
650 GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; | 623 AddNewChangestamp(change); |
651 if (entry->HasKey("gd$deleted") || entry->HasKey("docs$removed")) { | 624 error = HTTP_SUCCESS; |
652 error = HTTP_NOT_FOUND; | |
653 } else { | |
654 entry->Set("gd$deleted", new base::DictionaryValue); | |
655 AddNewChangestamp(entry); | |
656 error = HTTP_SUCCESS; | |
657 } | |
658 base::MessageLoop::current()->PostTask( | |
659 FROM_HERE, base::Bind(callback, error)); | |
660 return CancelCallback(); | |
661 } | |
662 } | 625 } |
| 626 base::MessageLoop::current()->PostTask( |
| 627 FROM_HERE, base::Bind(callback, error)); |
| 628 return CancelCallback(); |
663 } | 629 } |
664 | 630 |
665 base::MessageLoop::current()->PostTask( | 631 base::MessageLoop::current()->PostTask( |
666 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | 632 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); |
667 return CancelCallback(); | 633 return CancelCallback(); |
668 } | 634 } |
669 | 635 |
670 CancelCallback FakeDriveService::DownloadFile( | 636 CancelCallback FakeDriveService::DownloadFile( |
671 const base::FilePath& local_cache_path, | 637 const base::FilePath& local_cache_path, |
672 const std::string& resource_id, | 638 const std::string& resource_id, |
673 const DownloadActionCallback& download_action_callback, | 639 const DownloadActionCallback& download_action_callback, |
674 const GetContentCallback& get_content_callback, | 640 const GetContentCallback& get_content_callback, |
675 const ProgressCallback& progress_callback) { | 641 const ProgressCallback& progress_callback) { |
676 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 642 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
677 DCHECK(!download_action_callback.is_null()); | 643 DCHECK(!download_action_callback.is_null()); |
678 | 644 |
679 if (offline_) { | 645 if (offline_) { |
680 base::MessageLoop::current()->PostTask( | 646 base::MessageLoop::current()->PostTask( |
681 FROM_HERE, | 647 FROM_HERE, |
682 base::Bind(download_action_callback, | 648 base::Bind(download_action_callback, |
683 GDATA_NO_CONNECTION, | 649 GDATA_NO_CONNECTION, |
684 base::FilePath())); | 650 base::FilePath())); |
685 return CancelCallback(); | 651 return CancelCallback(); |
686 } | 652 } |
687 | 653 |
688 // The field content.src is the URL to download the file. | 654 EntryInfo* entry = FindEntryByResourceId(resource_id); |
689 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); | |
690 if (!entry) { | 655 if (!entry) { |
691 base::MessageLoopProxy::current()->PostTask( | 656 base::MessageLoopProxy::current()->PostTask( |
692 FROM_HERE, | 657 FROM_HERE, |
693 base::Bind(download_action_callback, HTTP_NOT_FOUND, base::FilePath())); | 658 base::Bind(download_action_callback, HTTP_NOT_FOUND, base::FilePath())); |
694 return CancelCallback(); | 659 return CancelCallback(); |
695 } | 660 } |
696 | 661 |
697 // Write "x"s of the file size specified in the entry. | 662 const FileResource* file = entry->change_resource.file(); |
698 std::string file_size_string; | 663 const std::string& content_data = entry->content_data; |
699 entry->GetString("docs$size.$t", &file_size_string); | 664 int64 file_size = file->file_size(); |
700 int64 file_size = 0; | 665 DCHECK_EQ(static_cast<size_t>(file_size), content_data.size()); |
701 if (base::StringToInt64(file_size_string, &file_size)) { | |
702 base::BinaryValue* content_binary_data; | |
703 std::string content_data; | |
704 if (entry->GetBinary("test$data", &content_binary_data)) { | |
705 content_data = std::string(content_binary_data->GetBuffer(), | |
706 content_binary_data->GetSize()); | |
707 } | |
708 DCHECK_EQ(static_cast<size_t>(file_size), content_data.size()); | |
709 | 666 |
710 if (!get_content_callback.is_null()) { | 667 if (!get_content_callback.is_null()) { |
711 const int64 kBlockSize = 5; | 668 const int64 kBlockSize = 5; |
712 for (int64 i = 0; i < file_size; i += kBlockSize) { | 669 for (int64 i = 0; i < file_size; i += kBlockSize) { |
713 const int64 size = std::min(kBlockSize, file_size - i); | 670 const int64 size = std::min(kBlockSize, file_size - i); |
714 scoped_ptr<std::string> content_for_callback( | 671 scoped_ptr<std::string> content_for_callback( |
715 new std::string(content_data.substr(i, size))); | 672 new std::string(content_data.substr(i, size))); |
716 base::MessageLoopProxy::current()->PostTask( | |
717 FROM_HERE, | |
718 base::Bind(get_content_callback, HTTP_SUCCESS, | |
719 base::Passed(&content_for_callback))); | |
720 } | |
721 } | |
722 | |
723 if (test_util::WriteStringToFile(local_cache_path, content_data)) { | |
724 if (!progress_callback.is_null()) { | |
725 // See also the comment in ResumeUpload(). For testing that clients | |
726 // can handle the case progress_callback is called multiple times, | |
727 // here we invoke the callback twice. | |
728 base::MessageLoopProxy::current()->PostTask( | |
729 FROM_HERE, | |
730 base::Bind(progress_callback, file_size / 2, file_size)); | |
731 base::MessageLoopProxy::current()->PostTask( | |
732 FROM_HERE, | |
733 base::Bind(progress_callback, file_size, file_size)); | |
734 } | |
735 base::MessageLoopProxy::current()->PostTask( | 673 base::MessageLoopProxy::current()->PostTask( |
736 FROM_HERE, | 674 FROM_HERE, |
737 base::Bind(download_action_callback, | 675 base::Bind(get_content_callback, HTTP_SUCCESS, |
738 HTTP_SUCCESS, | 676 base::Passed(&content_for_callback))); |
739 local_cache_path)); | |
740 return CancelCallback(); | |
741 } | 677 } |
742 } | 678 } |
743 | 679 |
| 680 if (test_util::WriteStringToFile(local_cache_path, content_data)) { |
| 681 if (!progress_callback.is_null()) { |
| 682 // See also the comment in ResumeUpload(). For testing that clients |
| 683 // can handle the case progress_callback is called multiple times, |
| 684 // here we invoke the callback twice. |
| 685 base::MessageLoopProxy::current()->PostTask( |
| 686 FROM_HERE, |
| 687 base::Bind(progress_callback, file_size / 2, file_size)); |
| 688 base::MessageLoopProxy::current()->PostTask( |
| 689 FROM_HERE, |
| 690 base::Bind(progress_callback, file_size, file_size)); |
| 691 } |
| 692 base::MessageLoopProxy::current()->PostTask( |
| 693 FROM_HERE, |
| 694 base::Bind(download_action_callback, |
| 695 HTTP_SUCCESS, |
| 696 local_cache_path)); |
| 697 return CancelCallback(); |
| 698 } |
| 699 |
744 // Failed to write the content. | 700 // Failed to write the content. |
745 base::MessageLoopProxy::current()->PostTask( | 701 base::MessageLoopProxy::current()->PostTask( |
746 FROM_HERE, | 702 FROM_HERE, |
747 base::Bind(download_action_callback, GDATA_FILE_ERROR, base::FilePath())); | 703 base::Bind(download_action_callback, GDATA_FILE_ERROR, base::FilePath())); |
748 return CancelCallback(); | 704 return CancelCallback(); |
749 } | 705 } |
750 | 706 |
751 CancelCallback FakeDriveService::CopyResource( | 707 CancelCallback FakeDriveService::CopyResource( |
752 const std::string& resource_id, | 708 const std::string& resource_id, |
753 const std::string& in_parent_resource_id, | 709 const std::string& in_parent_resource_id, |
754 const std::string& new_title, | 710 const std::string& new_title, |
755 const base::Time& last_modified, | 711 const base::Time& last_modified, |
756 const GetResourceEntryCallback& callback) { | 712 const GetResourceEntryCallback& callback) { |
757 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 713 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
758 DCHECK(!callback.is_null()); | 714 DCHECK(!callback.is_null()); |
759 | 715 |
760 if (offline_) { | 716 if (offline_) { |
761 scoped_ptr<ResourceEntry> null; | 717 scoped_ptr<ResourceEntry> null; |
762 base::MessageLoop::current()->PostTask( | 718 base::MessageLoop::current()->PostTask( |
763 FROM_HERE, | 719 FROM_HERE, |
764 base::Bind(callback, | 720 base::Bind(callback, |
765 GDATA_NO_CONNECTION, | 721 GDATA_NO_CONNECTION, |
766 base::Passed(&null))); | 722 base::Passed(&null))); |
767 return CancelCallback(); | 723 return CancelCallback(); |
768 } | 724 } |
769 | 725 |
770 const std::string& parent_resource_id = in_parent_resource_id.empty() ? | 726 const std::string& parent_resource_id = in_parent_resource_id.empty() ? |
771 GetRootResourceId() : in_parent_resource_id; | 727 GetRootResourceId() : in_parent_resource_id; |
772 | 728 |
773 base::ListValue* entries = NULL; | 729 EntryInfo* entry = FindEntryByResourceId(resource_id); |
774 // Go through entries and copy the one that matches |resource_id|. | 730 if (entry) { |
775 if (resource_list_value_->GetList("entry", &entries)) { | 731 // Make a copy and set the new resource ID and the new title. |
776 for (size_t i = 0; i < entries->GetSize(); ++i) { | 732 scoped_ptr<EntryInfo> copied_entry(new EntryInfo); |
777 base::DictionaryValue* entry = NULL; | 733 copied_entry->content_data = entry->content_data; |
778 std::string current_resource_id; | 734 copied_entry->share_url = entry->share_url; |
779 if (entries->GetDictionary(i, &entry) && | |
780 entry->GetString("gd$resourceId.$t", ¤t_resource_id) && | |
781 resource_id == current_resource_id) { | |
782 // Make a copy and set the new resource ID and the new title. | |
783 scoped_ptr<base::DictionaryValue> copied_entry(entry->DeepCopy()); | |
784 copied_entry->SetString("gd$resourceId.$t", GetNewResourceId()); | |
785 copied_entry->SetString("title.$t", new_title); | |
786 | 735 |
787 // Reset parent directory. | 736 // TODO(hashimoto): Implement a proper way to copy FileResource. |
788 base::ListValue* links = NULL; | 737 scoped_ptr<ResourceEntry> copied_resource_entry = |
789 if (!copied_entry->GetList("link", &links)) { | 738 util::ConvertChangeResourceToResourceEntry(entry->change_resource); |
790 links = new base::ListValue; | 739 copied_entry->change_resource.set_file( |
791 copied_entry->Set("link", links); | 740 util::ConvertResourceEntryToFileResource(*copied_resource_entry)); |
792 } | |
793 links->Clear(); | |
794 | 741 |
795 base::DictionaryValue* link = new base::DictionaryValue; | 742 ChangeResource* new_change = &copied_entry->change_resource; |
796 link->SetString( | 743 FileResource* new_file = new_change->mutable_file(); |
797 "rel", "http://schemas.google.com/docs/2007#parent"); | 744 const std::string new_resource_id = GetNewResourceId(); |
798 link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec()); | 745 new_change->set_file_id(new_resource_id); |
799 links->Append(link); | 746 new_file->set_file_id(new_resource_id); |
| 747 new_file->set_title(new_title); |
800 | 748 |
801 if (!last_modified.is_null()) { | 749 scoped_ptr<ParentReference> parent(new ParentReference); |
802 copied_entry->SetString( | 750 parent->set_file_id(parent_resource_id); |
803 "updated.$t", | 751 parent->set_parent_link(GetFakeLinkUrl(parent_resource_id)); |
804 google_apis::util::FormatTimeAsString(last_modified)); | 752 parent->set_is_root(parent_resource_id == GetRootResourceId()); |
805 } | 753 ScopedVector<ParentReference> parents; |
| 754 parents.push_back(parent.release()); |
| 755 new_file->set_parents(parents.Pass()); |
806 | 756 |
807 AddNewChangestamp(copied_entry.get()); | 757 if (!last_modified.is_null()) |
808 UpdateETag(copied_entry.get()); | 758 new_file->set_modified_date(last_modified); |
809 | 759 |
810 // Parse the new entry. | 760 AddNewChangestamp(new_change); |
811 scoped_ptr<ResourceEntry> resource_entry = | 761 UpdateETag(new_file); |
812 ResourceEntry::CreateFrom(*copied_entry); | |
813 // Add it to the resource list. | |
814 entries->Append(copied_entry.release()); | |
815 | 762 |
816 base::MessageLoop::current()->PostTask( | 763 scoped_ptr<ResourceEntry> resource_entry = |
817 FROM_HERE, | 764 util::ConvertChangeResourceToResourceEntry(*new_change); |
818 base::Bind(callback, | 765 // Add the new entry to the map. |
819 HTTP_SUCCESS, | 766 entries_[new_resource_id] = copied_entry.release(); |
820 base::Passed(&resource_entry))); | 767 |
821 return CancelCallback(); | 768 base::MessageLoop::current()->PostTask( |
822 } | 769 FROM_HERE, |
823 } | 770 base::Bind(callback, |
| 771 HTTP_SUCCESS, |
| 772 base::Passed(&resource_entry))); |
| 773 return CancelCallback(); |
824 } | 774 } |
825 | 775 |
826 scoped_ptr<ResourceEntry> null; | 776 scoped_ptr<ResourceEntry> null; |
827 base::MessageLoop::current()->PostTask( | 777 base::MessageLoop::current()->PostTask( |
828 FROM_HERE, | 778 FROM_HERE, |
829 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); | 779 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); |
830 return CancelCallback(); | 780 return CancelCallback(); |
831 } | 781 } |
832 | 782 |
833 CancelCallback FakeDriveService::UpdateResource( | 783 CancelCallback FakeDriveService::UpdateResource( |
834 const std::string& resource_id, | 784 const std::string& resource_id, |
835 const std::string& parent_resource_id, | 785 const std::string& parent_resource_id, |
836 const std::string& new_title, | 786 const std::string& new_title, |
837 const base::Time& last_modified, | 787 const base::Time& last_modified, |
838 const base::Time& last_viewed_by_me, | 788 const base::Time& last_viewed_by_me, |
839 const google_apis::GetResourceEntryCallback& callback) { | 789 const google_apis::GetResourceEntryCallback& callback) { |
840 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 790 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
841 DCHECK(!callback.is_null()); | 791 DCHECK(!callback.is_null()); |
842 | 792 |
843 if (offline_) { | 793 if (offline_) { |
844 base::MessageLoop::current()->PostTask( | 794 base::MessageLoop::current()->PostTask( |
845 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION, | 795 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION, |
846 base::Passed(scoped_ptr<ResourceEntry>()))); | 796 base::Passed(scoped_ptr<ResourceEntry>()))); |
847 return CancelCallback(); | 797 return CancelCallback(); |
848 } | 798 } |
849 | 799 |
850 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); | 800 EntryInfo* entry = FindEntryByResourceId(resource_id); |
851 if (entry) { | 801 if (entry) { |
852 entry->SetString("title.$t", new_title); | 802 ChangeResource* change = &entry->change_resource; |
| 803 FileResource* file = change->mutable_file(); |
| 804 file->set_title(new_title); |
853 | 805 |
854 // Set parent if necessary. | 806 // Set parent if necessary. |
855 if (!parent_resource_id.empty()) { | 807 if (!parent_resource_id.empty()) { |
856 base::ListValue* links = NULL; | 808 scoped_ptr<ParentReference> parent(new ParentReference); |
857 if (!entry->GetList("link", &links)) { | 809 parent->set_file_id(parent_resource_id); |
858 links = new base::ListValue; | 810 parent->set_parent_link(GetFakeLinkUrl(parent_resource_id)); |
859 entry->Set("link", links); | 811 parent->set_is_root(parent_resource_id == GetRootResourceId()); |
860 } | |
861 | 812 |
862 // Remove old parent(s). | 813 ScopedVector<ParentReference> parents; |
863 for (size_t i = 0; i < links->GetSize(); ) { | 814 parents.push_back(parent.release()); |
864 base::DictionaryValue* link = NULL; | 815 file->set_parents(parents.Pass()); |
865 std::string rel; | |
866 std::string href; | |
867 if (links->GetDictionary(i, &link) && | |
868 link->GetString("rel", &rel) && | |
869 link->GetString("href", &href) && | |
870 rel == "http://schemas.google.com/docs/2007#parent") { | |
871 links->Remove(i, NULL); | |
872 } else { | |
873 ++i; | |
874 } | |
875 } | |
876 | |
877 base::DictionaryValue* link = new base::DictionaryValue; | |
878 link->SetString("rel", "http://schemas.google.com/docs/2007#parent"); | |
879 link->SetString( | |
880 "href", GetFakeLinkUrl(parent_resource_id).spec()); | |
881 links->Append(link); | |
882 } | 816 } |
883 | 817 |
884 if (!last_modified.is_null()) { | 818 if (!last_modified.is_null()) |
885 entry->SetString( | 819 file->set_modified_date(last_modified); |
886 "updated.$t", | |
887 google_apis::util::FormatTimeAsString(last_modified)); | |
888 } | |
889 | 820 |
890 if (!last_viewed_by_me.is_null()) { | 821 if (!last_viewed_by_me.is_null()) |
891 entry->SetString( | 822 file->set_last_viewed_by_me_date(last_viewed_by_me); |
892 "gd$lastViewed.$t", | |
893 google_apis::util::FormatTimeAsString(last_viewed_by_me)); | |
894 } | |
895 | 823 |
896 AddNewChangestamp(entry); | 824 AddNewChangestamp(change); |
897 UpdateETag(entry); | 825 UpdateETag(file); |
898 | 826 |
899 // Parse the new entry. | |
900 scoped_ptr<ResourceEntry> resource_entry = | 827 scoped_ptr<ResourceEntry> resource_entry = |
901 ResourceEntry::CreateFrom(*entry); | 828 util::ConvertChangeResourceToResourceEntry(*change); |
902 base::MessageLoop::current()->PostTask( | 829 base::MessageLoop::current()->PostTask( |
903 FROM_HERE, | 830 FROM_HERE, |
904 base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_entry))); | 831 base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_entry))); |
905 return CancelCallback(); | 832 return CancelCallback(); |
906 } | 833 } |
907 | 834 |
908 base::MessageLoop::current()->PostTask( | 835 base::MessageLoop::current()->PostTask( |
909 FROM_HERE, | 836 FROM_HERE, |
910 base::Bind(callback, HTTP_NOT_FOUND, | 837 base::Bind(callback, HTTP_NOT_FOUND, |
911 base::Passed(scoped_ptr<ResourceEntry>()))); | 838 base::Passed(scoped_ptr<ResourceEntry>()))); |
(...skipping 18 matching lines...) Expand all Loading... |
930 const EntryActionCallback& callback) { | 857 const EntryActionCallback& callback) { |
931 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 858 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
932 DCHECK(!callback.is_null()); | 859 DCHECK(!callback.is_null()); |
933 | 860 |
934 if (offline_) { | 861 if (offline_) { |
935 base::MessageLoop::current()->PostTask( | 862 base::MessageLoop::current()->PostTask( |
936 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); | 863 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); |
937 return CancelCallback(); | 864 return CancelCallback(); |
938 } | 865 } |
939 | 866 |
940 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); | 867 EntryInfo* entry = FindEntryByResourceId(resource_id); |
941 if (entry) { | 868 if (entry) { |
942 base::ListValue* links = NULL; | 869 ChangeResource* change = &entry->change_resource; |
943 if (!entry->GetList("link", &links)) { | |
944 links = new base::ListValue; | |
945 entry->Set("link", links); | |
946 } | |
947 | |
948 // On the real Drive server, resources do not necessary shape a tree | 870 // On the real Drive server, resources do not necessary shape a tree |
949 // structure. That is, each resource can have multiple parent. | 871 // structure. That is, each resource can have multiple parent. |
950 // We mimic the behavior here; AddResourceToDirectoy just adds | 872 // We mimic the behavior here; AddResourceToDirectoy just adds |
951 // one more parent link, not overwriting old links. | 873 // one more parent, not overwriting old ones. |
952 base::DictionaryValue* link = new base::DictionaryValue; | 874 scoped_ptr<ParentReference> parent(new ParentReference); |
953 link->SetString("rel", "http://schemas.google.com/docs/2007#parent"); | 875 parent->set_file_id(parent_resource_id); |
954 link->SetString( | 876 parent->set_parent_link(GetFakeLinkUrl(parent_resource_id)); |
955 "href", GetFakeLinkUrl(parent_resource_id).spec()); | 877 parent->set_is_root(parent_resource_id == GetRootResourceId()); |
956 links->Append(link); | 878 change->mutable_file()->mutable_parents()->push_back(parent.release()); |
957 | 879 |
958 AddNewChangestamp(entry); | 880 AddNewChangestamp(change); |
959 base::MessageLoop::current()->PostTask( | 881 base::MessageLoop::current()->PostTask( |
960 FROM_HERE, base::Bind(callback, HTTP_SUCCESS)); | 882 FROM_HERE, base::Bind(callback, HTTP_SUCCESS)); |
961 return CancelCallback(); | 883 return CancelCallback(); |
962 } | 884 } |
963 | 885 |
964 base::MessageLoop::current()->PostTask( | 886 base::MessageLoop::current()->PostTask( |
965 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | 887 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); |
966 return CancelCallback(); | 888 return CancelCallback(); |
967 } | 889 } |
968 | 890 |
969 CancelCallback FakeDriveService::RemoveResourceFromDirectory( | 891 CancelCallback FakeDriveService::RemoveResourceFromDirectory( |
970 const std::string& parent_resource_id, | 892 const std::string& parent_resource_id, |
971 const std::string& resource_id, | 893 const std::string& resource_id, |
972 const EntryActionCallback& callback) { | 894 const EntryActionCallback& callback) { |
973 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 895 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
974 DCHECK(!callback.is_null()); | 896 DCHECK(!callback.is_null()); |
975 | 897 |
976 if (offline_) { | 898 if (offline_) { |
977 base::MessageLoop::current()->PostTask( | 899 base::MessageLoop::current()->PostTask( |
978 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); | 900 FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION)); |
979 return CancelCallback(); | 901 return CancelCallback(); |
980 } | 902 } |
981 | 903 |
982 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); | 904 EntryInfo* entry = FindEntryByResourceId(resource_id); |
983 if (entry) { | 905 if (entry) { |
984 base::ListValue* links = NULL; | 906 ChangeResource* change = &entry->change_resource; |
985 if (entry->GetList("link", &links)) { | 907 FileResource* file = change->mutable_file(); |
986 GURL parent_content_url = GetFakeLinkUrl(parent_resource_id); | 908 ScopedVector<ParentReference>* parents = file->mutable_parents(); |
987 for (size_t i = 0; i < links->GetSize(); ++i) { | 909 for (size_t i = 0; i < parents->size(); ++i) { |
988 base::DictionaryValue* link = NULL; | 910 if ((*parents)[i]->file_id() == parent_resource_id) { |
989 std::string rel; | 911 parents->erase(parents->begin() + i); |
990 std::string href; | 912 AddNewChangestamp(change); |
991 if (links->GetDictionary(i, &link) && | 913 base::MessageLoop::current()->PostTask( |
992 link->GetString("rel", &rel) && | 914 FROM_HERE, base::Bind(callback, HTTP_NO_CONTENT)); |
993 link->GetString("href", &href) && | 915 return CancelCallback(); |
994 rel == "http://schemas.google.com/docs/2007#parent" && | |
995 GURL(href) == parent_content_url) { | |
996 links->Remove(i, NULL); | |
997 AddNewChangestamp(entry); | |
998 base::MessageLoop::current()->PostTask( | |
999 FROM_HERE, base::Bind(callback, HTTP_NO_CONTENT)); | |
1000 return CancelCallback(); | |
1001 } | |
1002 } | 916 } |
1003 } | 917 } |
1004 } | 918 } |
1005 | 919 |
1006 base::MessageLoop::current()->PostTask( | 920 base::MessageLoop::current()->PostTask( |
1007 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); | 921 FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND)); |
1008 return CancelCallback(); | 922 return CancelCallback(); |
1009 } | 923 } |
1010 | 924 |
1011 CancelCallback FakeDriveService::AddNewDirectory( | 925 CancelCallback FakeDriveService::AddNewDirectory( |
1012 const std::string& parent_resource_id, | 926 const std::string& parent_resource_id, |
1013 const std::string& directory_title, | 927 const std::string& directory_title, |
1014 const GetResourceEntryCallback& callback) { | 928 const GetResourceEntryCallback& callback) { |
1015 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 929 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1016 DCHECK(!callback.is_null()); | 930 DCHECK(!callback.is_null()); |
1017 | 931 |
1018 if (offline_) { | 932 if (offline_) { |
1019 scoped_ptr<ResourceEntry> null; | 933 scoped_ptr<ResourceEntry> null; |
1020 base::MessageLoop::current()->PostTask( | 934 base::MessageLoop::current()->PostTask( |
1021 FROM_HERE, | 935 FROM_HERE, |
1022 base::Bind(callback, | 936 base::Bind(callback, |
1023 GDATA_NO_CONNECTION, | 937 GDATA_NO_CONNECTION, |
1024 base::Passed(&null))); | 938 base::Passed(&null))); |
1025 return CancelCallback(); | 939 return CancelCallback(); |
1026 } | 940 } |
1027 | 941 |
1028 const char kContentType[] = "application/atom+xml;type=feed"; | 942 const EntryInfo* new_entry = AddNewEntry(kDriveFolderMimeType, |
1029 const base::DictionaryValue* new_entry = AddNewEntry(kContentType, | 943 "", // content_data |
1030 "", // content_data | 944 parent_resource_id, |
1031 parent_resource_id, | 945 directory_title, |
1032 directory_title, | 946 false); // shared_with_me |
1033 false, // shared_with_me | |
1034 "folder"); | |
1035 if (!new_entry) { | 947 if (!new_entry) { |
1036 scoped_ptr<ResourceEntry> null; | 948 scoped_ptr<ResourceEntry> null; |
1037 base::MessageLoop::current()->PostTask( | 949 base::MessageLoop::current()->PostTask( |
1038 FROM_HERE, | 950 FROM_HERE, |
1039 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); | 951 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); |
1040 return CancelCallback(); | 952 return CancelCallback(); |
1041 } | 953 } |
1042 | 954 |
1043 scoped_ptr<ResourceEntry> parsed_entry(ResourceEntry::CreateFrom(*new_entry)); | 955 scoped_ptr<ResourceEntry> parsed_entry( |
| 956 util::ConvertChangeResourceToResourceEntry(new_entry->change_resource)); |
1044 base::MessageLoop::current()->PostTask( | 957 base::MessageLoop::current()->PostTask( |
1045 FROM_HERE, | 958 FROM_HERE, |
1046 base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry))); | 959 base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry))); |
1047 return CancelCallback(); | 960 return CancelCallback(); |
1048 } | 961 } |
1049 | 962 |
1050 CancelCallback FakeDriveService::InitiateUploadNewFile( | 963 CancelCallback FakeDriveService::InitiateUploadNewFile( |
1051 const std::string& content_type, | 964 const std::string& content_type, |
1052 int64 content_length, | 965 int64 content_length, |
1053 const std::string& parent_resource_id, | 966 const std::string& parent_resource_id, |
1054 const std::string& title, | 967 const std::string& title, |
1055 const InitiateUploadCallback& callback) { | 968 const InitiateUploadCallback& callback) { |
1056 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 969 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1057 DCHECK(!callback.is_null()); | 970 DCHECK(!callback.is_null()); |
1058 | 971 |
1059 if (offline_) { | 972 if (offline_) { |
1060 base::MessageLoop::current()->PostTask( | 973 base::MessageLoop::current()->PostTask( |
1061 FROM_HERE, | 974 FROM_HERE, |
1062 base::Bind(callback, GDATA_NO_CONNECTION, GURL())); | 975 base::Bind(callback, GDATA_NO_CONNECTION, GURL())); |
1063 return CancelCallback(); | 976 return CancelCallback(); |
1064 } | 977 } |
1065 | 978 |
1066 if (parent_resource_id != GetRootResourceId() && | 979 if (parent_resource_id != GetRootResourceId() && |
1067 !FindEntryByResourceId(parent_resource_id)) { | 980 !entries_.count(parent_resource_id)) { |
1068 base::MessageLoop::current()->PostTask( | 981 base::MessageLoop::current()->PostTask( |
1069 FROM_HERE, | 982 FROM_HERE, |
1070 base::Bind(callback, HTTP_NOT_FOUND, GURL())); | 983 base::Bind(callback, HTTP_NOT_FOUND, GURL())); |
1071 return CancelCallback(); | 984 return CancelCallback(); |
1072 } | 985 } |
1073 | 986 |
1074 GURL session_url = GetNewUploadSessionUrl(); | 987 GURL session_url = GetNewUploadSessionUrl(); |
1075 upload_sessions_[session_url] = | 988 upload_sessions_[session_url] = |
1076 UploadSession(content_type, content_length, | 989 UploadSession(content_type, content_length, |
1077 parent_resource_id, | 990 parent_resource_id, |
(...skipping 16 matching lines...) Expand all Loading... |
1094 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1007 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1095 DCHECK(!callback.is_null()); | 1008 DCHECK(!callback.is_null()); |
1096 | 1009 |
1097 if (offline_) { | 1010 if (offline_) { |
1098 base::MessageLoop::current()->PostTask( | 1011 base::MessageLoop::current()->PostTask( |
1099 FROM_HERE, | 1012 FROM_HERE, |
1100 base::Bind(callback, GDATA_NO_CONNECTION, GURL())); | 1013 base::Bind(callback, GDATA_NO_CONNECTION, GURL())); |
1101 return CancelCallback(); | 1014 return CancelCallback(); |
1102 } | 1015 } |
1103 | 1016 |
1104 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); | 1017 EntryInfo* entry = FindEntryByResourceId(resource_id); |
1105 if (!entry) { | 1018 if (!entry) { |
1106 base::MessageLoop::current()->PostTask( | 1019 base::MessageLoop::current()->PostTask( |
1107 FROM_HERE, | 1020 FROM_HERE, |
1108 base::Bind(callback, HTTP_NOT_FOUND, GURL())); | 1021 base::Bind(callback, HTTP_NOT_FOUND, GURL())); |
1109 return CancelCallback(); | 1022 return CancelCallback(); |
1110 } | 1023 } |
1111 | 1024 |
1112 std::string entry_etag; | 1025 const FileResource* file = entry->change_resource.file(); |
1113 entry->GetString("gd$etag", &entry_etag); | 1026 if (!etag.empty() && etag != file->etag()) { |
1114 if (!etag.empty() && etag != entry_etag) { | |
1115 base::MessageLoop::current()->PostTask( | 1027 base::MessageLoop::current()->PostTask( |
1116 FROM_HERE, | 1028 FROM_HERE, |
1117 base::Bind(callback, HTTP_PRECONDITION, GURL())); | 1029 base::Bind(callback, HTTP_PRECONDITION, GURL())); |
1118 return CancelCallback(); | 1030 return CancelCallback(); |
1119 } | 1031 } |
1120 | 1032 |
1121 GURL session_url = GetNewUploadSessionUrl(); | 1033 GURL session_url = GetNewUploadSessionUrl(); |
1122 upload_sessions_[session_url] = | 1034 upload_sessions_[session_url] = |
1123 UploadSession(content_type, content_length, | 1035 UploadSession(content_type, content_length, |
1124 "", // parent_resource_id | 1036 "", // parent_resource_id |
1125 resource_id, | 1037 resource_id, |
1126 entry_etag, | 1038 file->etag(), |
1127 "" /* title */); | 1039 "" /* title */); |
1128 | 1040 |
1129 base::MessageLoop::current()->PostTask( | 1041 base::MessageLoop::current()->PostTask( |
1130 FROM_HERE, | 1042 FROM_HERE, |
1131 base::Bind(callback, HTTP_SUCCESS, session_url)); | 1043 base::Bind(callback, HTTP_SUCCESS, session_url)); |
1132 return CancelCallback(); | 1044 return CancelCallback(); |
1133 } | 1045 } |
1134 | 1046 |
1135 CancelCallback FakeDriveService::GetUploadStatus( | 1047 CancelCallback FakeDriveService::GetUploadStatus( |
1136 const GURL& upload_url, | 1048 const GURL& upload_url, |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1202 session->uploaded_size = end_position; | 1114 session->uploaded_size = end_position; |
1203 completion_callback.Run(GDATA_FILE_ERROR, scoped_ptr<ResourceEntry>()); | 1115 completion_callback.Run(GDATA_FILE_ERROR, scoped_ptr<ResourceEntry>()); |
1204 return CancelCallback(); | 1116 return CancelCallback(); |
1205 } | 1117 } |
1206 session->uploaded_size = end_position; | 1118 session->uploaded_size = end_position; |
1207 | 1119 |
1208 // |resource_id| is empty if the upload is for new file. | 1120 // |resource_id| is empty if the upload is for new file. |
1209 if (session->resource_id.empty()) { | 1121 if (session->resource_id.empty()) { |
1210 DCHECK(!session->parent_resource_id.empty()); | 1122 DCHECK(!session->parent_resource_id.empty()); |
1211 DCHECK(!session->title.empty()); | 1123 DCHECK(!session->title.empty()); |
1212 const base::DictionaryValue* new_entry = AddNewEntry( | 1124 const EntryInfo* new_entry = AddNewEntry( |
1213 session->content_type, | 1125 session->content_type, |
1214 content_data, | 1126 content_data, |
1215 session->parent_resource_id, | 1127 session->parent_resource_id, |
1216 session->title, | 1128 session->title, |
1217 false, // shared_with_me | 1129 false); // shared_with_me |
1218 "file"); | |
1219 if (!new_entry) { | 1130 if (!new_entry) { |
1220 completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>()); | 1131 completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>()); |
1221 return CancelCallback(); | 1132 return CancelCallback(); |
1222 } | 1133 } |
1223 | 1134 |
1224 completion_callback.Run(HTTP_CREATED, | 1135 completion_callback.Run( |
1225 ResourceEntry::CreateFrom(*new_entry)); | 1136 HTTP_CREATED, |
| 1137 util::ConvertChangeResourceToResourceEntry(new_entry->change_resource)); |
1226 return CancelCallback(); | 1138 return CancelCallback(); |
1227 } | 1139 } |
1228 | 1140 |
1229 base::DictionaryValue* entry = FindEntryByResourceId(session->resource_id); | 1141 EntryInfo* entry = FindEntryByResourceId(session->resource_id); |
1230 if (!entry) { | 1142 if (!entry) { |
1231 completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>()); | 1143 completion_callback.Run(HTTP_NOT_FOUND, scoped_ptr<ResourceEntry>()); |
1232 return CancelCallback(); | 1144 return CancelCallback(); |
1233 } | 1145 } |
1234 | 1146 |
1235 std::string entry_etag; | 1147 ChangeResource* change = &entry->change_resource; |
1236 entry->GetString("gd$etag", &entry_etag); | 1148 FileResource* file = change->mutable_file(); |
1237 if (entry_etag.empty() || session->etag != entry_etag) { | 1149 if (file->etag().empty() || session->etag != file->etag()) { |
1238 completion_callback.Run(HTTP_PRECONDITION, scoped_ptr<ResourceEntry>()); | 1150 completion_callback.Run(HTTP_PRECONDITION, scoped_ptr<ResourceEntry>()); |
1239 return CancelCallback(); | 1151 return CancelCallback(); |
1240 } | 1152 } |
1241 | 1153 |
1242 entry->SetString("docs$md5Checksum.$t", base::MD5String(content_data)); | 1154 file->set_md5_checksum(base::MD5String(content_data)); |
1243 entry->Set("test$data", | 1155 entry->content_data = content_data; |
1244 base::BinaryValue::CreateWithCopiedBuffer( | 1156 file->set_file_size(end_position); |
1245 content_data.data(), content_data.size())); | 1157 AddNewChangestamp(change); |
1246 entry->SetString("docs$size.$t", base::Int64ToString(end_position)); | 1158 UpdateETag(file); |
1247 AddNewChangestamp(entry); | |
1248 UpdateETag(entry); | |
1249 | 1159 |
1250 completion_callback.Run(HTTP_SUCCESS, ResourceEntry::CreateFrom(*entry)); | 1160 completion_callback.Run(HTTP_SUCCESS, |
| 1161 util::ConvertChangeResourceToResourceEntry(*change)); |
1251 return CancelCallback(); | 1162 return CancelCallback(); |
1252 } | 1163 } |
1253 | 1164 |
1254 CancelCallback FakeDriveService::AuthorizeApp( | 1165 CancelCallback FakeDriveService::AuthorizeApp( |
1255 const std::string& resource_id, | 1166 const std::string& resource_id, |
1256 const std::string& app_id, | 1167 const std::string& app_id, |
1257 const AuthorizeAppCallback& callback) { | 1168 const AuthorizeAppCallback& callback) { |
1258 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1259 DCHECK(!callback.is_null()); | 1170 DCHECK(!callback.is_null()); |
1260 return CancelCallback(); | 1171 return CancelCallback(); |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1361 if (offline_) { | 1272 if (offline_) { |
1362 scoped_ptr<ResourceEntry> null; | 1273 scoped_ptr<ResourceEntry> null; |
1363 base::MessageLoop::current()->PostTask( | 1274 base::MessageLoop::current()->PostTask( |
1364 FROM_HERE, | 1275 FROM_HERE, |
1365 base::Bind(callback, | 1276 base::Bind(callback, |
1366 GDATA_NO_CONNECTION, | 1277 GDATA_NO_CONNECTION, |
1367 base::Passed(&null))); | 1278 base::Passed(&null))); |
1368 return; | 1279 return; |
1369 } | 1280 } |
1370 | 1281 |
1371 // Prepare "kind" for hosted documents. This only supports Google Document. | 1282 const EntryInfo* new_entry = AddNewEntry(content_type, |
1372 std::string entry_kind; | 1283 content_data, |
1373 if (content_type == "application/vnd.google-apps.document") | 1284 parent_resource_id, |
1374 entry_kind = "document"; | 1285 title, |
1375 else | 1286 shared_with_me); |
1376 entry_kind = "file"; | |
1377 | |
1378 const base::DictionaryValue* new_entry = AddNewEntry(content_type, | |
1379 content_data, | |
1380 parent_resource_id, | |
1381 title, | |
1382 shared_with_me, | |
1383 entry_kind); | |
1384 if (!new_entry) { | 1287 if (!new_entry) { |
1385 scoped_ptr<ResourceEntry> null; | 1288 scoped_ptr<ResourceEntry> null; |
1386 base::MessageLoop::current()->PostTask( | 1289 base::MessageLoop::current()->PostTask( |
1387 FROM_HERE, | 1290 FROM_HERE, |
1388 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); | 1291 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); |
1389 return; | 1292 return; |
1390 } | 1293 } |
1391 | 1294 |
1392 scoped_ptr<ResourceEntry> parsed_entry( | 1295 scoped_ptr<ResourceEntry> parsed_entry( |
1393 ResourceEntry::CreateFrom(*new_entry)); | 1296 util::ConvertChangeResourceToResourceEntry(new_entry->change_resource)); |
1394 base::MessageLoop::current()->PostTask( | 1297 base::MessageLoop::current()->PostTask( |
1395 FROM_HERE, | 1298 FROM_HERE, |
1396 base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry))); | 1299 base::Bind(callback, HTTP_CREATED, base::Passed(&parsed_entry))); |
1397 } | 1300 } |
1398 | 1301 |
1399 void FakeDriveService::SetLastModifiedTime( | 1302 void FakeDriveService::SetLastModifiedTime( |
1400 const std::string& resource_id, | 1303 const std::string& resource_id, |
1401 const base::Time& last_modified_time, | 1304 const base::Time& last_modified_time, |
1402 const GetResourceEntryCallback& callback) { | 1305 const GetResourceEntryCallback& callback) { |
1403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1306 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1404 DCHECK(!callback.is_null()); | 1307 DCHECK(!callback.is_null()); |
1405 | 1308 |
1406 if (offline_) { | 1309 if (offline_) { |
1407 scoped_ptr<ResourceEntry> null; | 1310 scoped_ptr<ResourceEntry> null; |
1408 base::MessageLoop::current()->PostTask( | 1311 base::MessageLoop::current()->PostTask( |
1409 FROM_HERE, | 1312 FROM_HERE, |
1410 base::Bind(callback, | 1313 base::Bind(callback, |
1411 GDATA_NO_CONNECTION, | 1314 GDATA_NO_CONNECTION, |
1412 base::Passed(&null))); | 1315 base::Passed(&null))); |
1413 return; | 1316 return; |
1414 } | 1317 } |
1415 | 1318 |
1416 base::DictionaryValue* entry = FindEntryByResourceId(resource_id); | 1319 EntryInfo* entry = FindEntryByResourceId(resource_id); |
1417 if (!entry) { | 1320 if (!entry) { |
1418 scoped_ptr<ResourceEntry> null; | 1321 scoped_ptr<ResourceEntry> null; |
1419 base::MessageLoop::current()->PostTask( | 1322 base::MessageLoop::current()->PostTask( |
1420 FROM_HERE, | 1323 FROM_HERE, |
1421 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); | 1324 base::Bind(callback, HTTP_NOT_FOUND, base::Passed(&null))); |
1422 return; | 1325 return; |
1423 } | 1326 } |
1424 | 1327 |
1425 if (last_modified_time.is_null()) { | 1328 ChangeResource* change = &entry->change_resource; |
1426 entry->Remove("updated.$t", NULL); | 1329 FileResource* file = change->mutable_file(); |
1427 } else { | 1330 file->set_modified_date(last_modified_time); |
1428 entry->SetString( | |
1429 "updated.$t", | |
1430 google_apis::util::FormatTimeAsString(last_modified_time)); | |
1431 } | |
1432 | 1331 |
1433 scoped_ptr<ResourceEntry> parsed_entry( | 1332 scoped_ptr<ResourceEntry> parsed_entry( |
1434 ResourceEntry::CreateFrom(*entry)); | 1333 util::ConvertChangeResourceToResourceEntry(*change)); |
1435 base::MessageLoop::current()->PostTask( | 1334 base::MessageLoop::current()->PostTask( |
1436 FROM_HERE, | 1335 FROM_HERE, |
1437 base::Bind(callback, HTTP_SUCCESS, base::Passed(&parsed_entry))); | 1336 base::Bind(callback, HTTP_SUCCESS, base::Passed(&parsed_entry))); |
1438 } | 1337 } |
1439 | 1338 |
1440 base::DictionaryValue* FakeDriveService::FindEntryByResourceId( | 1339 FakeDriveService::EntryInfo* FakeDriveService::FindEntryByResourceId( |
1441 const std::string& resource_id) { | 1340 const std::string& resource_id) { |
1442 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1443 | 1342 |
1444 base::ListValue* entries = NULL; | 1343 EntryInfoMap::iterator it = entries_.find(resource_id); |
1445 // Go through entries and return the one that matches |resource_id|. | 1344 // Deleted entries don't have FileResource. |
1446 if (resource_list_value_->GetList("entry", &entries)) { | 1345 return it != entries_.end() && it->second->change_resource.file() ? |
1447 for (size_t i = 0; i < entries->GetSize(); ++i) { | 1346 it->second : NULL; |
1448 base::DictionaryValue* entry = NULL; | |
1449 std::string current_resource_id; | |
1450 if (entries->GetDictionary(i, &entry) && | |
1451 entry->GetString("gd$resourceId.$t", ¤t_resource_id) && | |
1452 resource_id == current_resource_id && | |
1453 !entry->HasKey("docs$removed")) { | |
1454 return entry; | |
1455 } | |
1456 } | |
1457 } | |
1458 | |
1459 return NULL; | |
1460 } | |
1461 | |
1462 base::DictionaryValue* FakeDriveService::FindEntryByContentUrl( | |
1463 const GURL& content_url) { | |
1464 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
1465 | |
1466 base::ListValue* entries = NULL; | |
1467 // Go through entries and return the one that matches |content_url|. | |
1468 if (resource_list_value_->GetList("entry", &entries)) { | |
1469 for (size_t i = 0; i < entries->GetSize(); ++i) { | |
1470 base::DictionaryValue* entry = NULL; | |
1471 std::string current_content_url; | |
1472 if (entries->GetDictionary(i, &entry) && | |
1473 entry->GetString("content.src", ¤t_content_url) && | |
1474 content_url == GURL(current_content_url)) { | |
1475 return entry; | |
1476 } | |
1477 } | |
1478 } | |
1479 | |
1480 return NULL; | |
1481 } | 1347 } |
1482 | 1348 |
1483 std::string FakeDriveService::GetNewResourceId() { | 1349 std::string FakeDriveService::GetNewResourceId() { |
1484 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1350 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1485 | 1351 |
1486 ++resource_id_count_; | 1352 ++resource_id_count_; |
1487 return base::StringPrintf("resource_id_%d", resource_id_count_); | 1353 return base::StringPrintf("resource_id_%d", resource_id_count_); |
1488 } | 1354 } |
1489 | 1355 |
1490 void FakeDriveService::UpdateETag(base::DictionaryValue* entry) { | 1356 void FakeDriveService::UpdateETag(google_apis::FileResource* file) { |
1491 entry->SetString("gd$etag", | 1357 file->set_etag("etag_" + base::Int64ToString(largest_changestamp_)); |
1492 "etag_" + base::Int64ToString(largest_changestamp_)); | |
1493 } | 1358 } |
1494 | 1359 |
1495 void FakeDriveService::AddNewChangestamp(base::DictionaryValue* entry) { | 1360 void FakeDriveService::AddNewChangestamp(google_apis::ChangeResource* change) { |
1496 ++largest_changestamp_; | 1361 ++largest_changestamp_; |
1497 entry->SetString("docs$changestamp.value", | 1362 change->set_change_id(largest_changestamp_); |
1498 base::Int64ToString(largest_changestamp_)); | |
1499 } | 1363 } |
1500 | 1364 |
1501 const base::DictionaryValue* FakeDriveService::AddNewEntry( | 1365 const FakeDriveService::EntryInfo* FakeDriveService::AddNewEntry( |
1502 const std::string& content_type, | 1366 const std::string& content_type, |
1503 const std::string& content_data, | 1367 const std::string& content_data, |
1504 const std::string& parent_resource_id, | 1368 const std::string& parent_resource_id, |
1505 const std::string& title, | 1369 const std::string& title, |
1506 bool shared_with_me, | 1370 bool shared_with_me) { |
1507 const std::string& entry_kind) { | |
1508 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1509 | 1372 |
1510 if (!parent_resource_id.empty() && | 1373 if (!parent_resource_id.empty() && |
1511 parent_resource_id != GetRootResourceId() && | 1374 parent_resource_id != GetRootResourceId() && |
1512 !FindEntryByResourceId(parent_resource_id)) { | 1375 !entries_.count(parent_resource_id)) { |
1513 return NULL; | 1376 return NULL; |
1514 } | 1377 } |
1515 | 1378 |
1516 std::string resource_id = GetNewResourceId(); | 1379 std::string resource_id = GetNewResourceId(); |
1517 GURL upload_url = GURL("https://xxx/upload/" + resource_id); | 1380 GURL upload_url = GURL("https://xxx/upload/" + resource_id); |
1518 | 1381 |
1519 scoped_ptr<base::DictionaryValue> new_entry(new base::DictionaryValue); | 1382 scoped_ptr<EntryInfo> new_entry(new EntryInfo); |
| 1383 ChangeResource* new_change = &new_entry->change_resource; |
| 1384 FileResource* new_file = new FileResource; |
| 1385 new_change->set_file(make_scoped_ptr(new_file)); |
| 1386 |
1520 // Set the resource ID and the title | 1387 // Set the resource ID and the title |
1521 new_entry->SetString("gd$resourceId.$t", resource_id); | 1388 new_change->set_file_id(resource_id); |
1522 new_entry->SetString("title.$t", title); | 1389 new_file->set_file_id(resource_id); |
1523 new_entry->SetString("docs$filename", title); | 1390 new_file->set_title(title); |
1524 // Set the contents, size and MD5 for a file. | 1391 // Set the contents, size and MD5 for a file. |
1525 if (entry_kind == "file") { | 1392 if (content_type != kDriveFolderMimeType) { |
1526 new_entry->Set("test$data", | 1393 new_entry->content_data = content_data; |
1527 base::BinaryValue::CreateWithCopiedBuffer( | 1394 new_file->set_file_size(content_data.size()); |
1528 content_data.c_str(), content_data.size())); | 1395 new_file->set_md5_checksum(base::MD5String(content_data)); |
1529 new_entry->SetString("docs$size.$t", | |
1530 base::Int64ToString(content_data.size())); | |
1531 new_entry->SetString("docs$md5Checksum.$t", | |
1532 base::MD5String(content_data)); | |
1533 } | 1396 } |
1534 | 1397 |
1535 // Add "category" which sets the resource type to |entry_kind|. | |
1536 base::ListValue* categories = new base::ListValue; | |
1537 base::DictionaryValue* category = new base::DictionaryValue; | |
1538 category->SetString("scheme", "http://schemas.google.com/g/2005#kind"); | |
1539 category->SetString("term", "http://schemas.google.com/docs/2007#" + | |
1540 entry_kind); | |
1541 categories->Append(category); | |
1542 new_entry->Set("category", categories); | |
1543 if (shared_with_me) { | 1398 if (shared_with_me) { |
1544 base::DictionaryValue* shared_with_me_label = new base::DictionaryValue; | 1399 // Set current time to mark the file as shared_with_me. |
1545 shared_with_me_label->SetString("label", "shared-with-me"); | 1400 new_file->set_shared_with_me_date(base::Time::Now()); |
1546 shared_with_me_label->SetString("scheme", | |
1547 "http://schemas.google.com/g/2005/labels"); | |
1548 shared_with_me_label->SetString( | |
1549 "term", "http://schemas.google.com/g/2005/labels#shared"); | |
1550 categories->Append(shared_with_me_label); | |
1551 } | 1401 } |
1552 | 1402 |
1553 std::string escaped_resource_id = net::EscapePath(resource_id); | 1403 std::string escaped_resource_id = net::EscapePath(resource_id); |
1554 | 1404 |
1555 // Add "content" which sets the content URL. | 1405 // Set download URL and mime type. |
1556 base::DictionaryValue* content = new base::DictionaryValue; | 1406 new_file->set_download_url( |
1557 content->SetString("src", "https://xxx/content/" + escaped_resource_id); | 1407 GURL("https://xxx/content/" + escaped_resource_id)); |
1558 content->SetString("type", content_type); | 1408 new_file->set_mime_type(content_type); |
1559 new_entry->Set("content", content); | |
1560 | 1409 |
1561 // Add "link" which sets the parent URL, the edit URL and the upload URL. | 1410 // Set parents. |
1562 base::ListValue* links = new base::ListValue; | 1411 scoped_ptr<ParentReference> parent(new ParentReference); |
| 1412 if (parent_resource_id.empty()) |
| 1413 parent->set_file_id(GetRootResourceId()); |
| 1414 else |
| 1415 parent->set_file_id(parent_resource_id); |
| 1416 parent->set_parent_link(GetFakeLinkUrl(parent->file_id())); |
| 1417 parent->set_is_root(parent->file_id() == GetRootResourceId()); |
| 1418 ScopedVector<ParentReference> parents; |
| 1419 parents.push_back(parent.release()); |
| 1420 new_file->set_parents(parents.Pass()); |
1563 | 1421 |
1564 base::DictionaryValue* parent_link = new base::DictionaryValue; | 1422 new_file->set_self_link(GURL("https://xxx/edit/" + escaped_resource_id)); |
1565 if (parent_resource_id.empty()) | |
1566 parent_link->SetString("href", GetFakeLinkUrl(GetRootResourceId()).spec()); | |
1567 else | |
1568 parent_link->SetString("href", GetFakeLinkUrl(parent_resource_id).spec()); | |
1569 parent_link->SetString("rel", | |
1570 "http://schemas.google.com/docs/2007#parent"); | |
1571 links->Append(parent_link); | |
1572 | 1423 |
1573 base::DictionaryValue* edit_link = new base::DictionaryValue; | 1424 new_entry->share_url = net::AppendOrReplaceQueryParameter( |
1574 edit_link->SetString("href", "https://xxx/edit/" + escaped_resource_id); | 1425 share_url_base_, "name", title); |
1575 edit_link->SetString("rel", "edit"); | |
1576 links->Append(edit_link); | |
1577 | 1426 |
1578 base::DictionaryValue* upload_link = new base::DictionaryValue; | 1427 AddNewChangestamp(new_change); |
1579 upload_link->SetString("href", upload_url.spec()); | 1428 UpdateETag(new_file); |
1580 upload_link->SetString("rel", kUploadUrlRel); | |
1581 links->Append(upload_link); | |
1582 | |
1583 const GURL share_url = net::AppendOrReplaceQueryParameter( | |
1584 share_url_base_, "name", title); | |
1585 base::DictionaryValue* share_link = new base::DictionaryValue; | |
1586 upload_link->SetString("href", share_url.spec()); | |
1587 upload_link->SetString("rel", kShareUrlRel); | |
1588 links->Append(share_link); | |
1589 new_entry->Set("link", links); | |
1590 | |
1591 AddNewChangestamp(new_entry.get()); | |
1592 UpdateETag(new_entry.get()); | |
1593 | 1429 |
1594 base::Time published_date = | 1430 base::Time published_date = |
1595 base::Time() + base::TimeDelta::FromMilliseconds(++published_date_seq_); | 1431 base::Time() + base::TimeDelta::FromMilliseconds(++published_date_seq_); |
1596 new_entry->SetString( | 1432 new_file->set_created_date(published_date); |
1597 "published.$t", | |
1598 google_apis::util::FormatTimeAsString(published_date)); | |
1599 | 1433 |
1600 // If there are no entries, prepare an empty entry to add. | 1434 EntryInfo* raw_new_entry = new_entry.release(); |
1601 if (!resource_list_value_->HasKey("entry")) | 1435 entries_[resource_id] = raw_new_entry; |
1602 resource_list_value_->Set("entry", new base::ListValue); | |
1603 | |
1604 base::DictionaryValue* raw_new_entry = new_entry.release(); | |
1605 base::ListValue* entries = NULL; | |
1606 if (resource_list_value_->GetList("entry", &entries)) | |
1607 entries->Append(raw_new_entry); | |
1608 | |
1609 return raw_new_entry; | 1436 return raw_new_entry; |
1610 } | 1437 } |
1611 | 1438 |
1612 void FakeDriveService::GetResourceListInternal( | 1439 void FakeDriveService::GetResourceListInternal( |
1613 int64 start_changestamp, | 1440 int64 start_changestamp, |
1614 const std::string& search_query, | 1441 const std::string& search_query, |
1615 const std::string& directory_resource_id, | 1442 const std::string& directory_resource_id, |
1616 int start_offset, | 1443 int start_offset, |
1617 int max_results, | 1444 int max_results, |
1618 int* load_counter, | 1445 int* load_counter, |
1619 const GetResourceListCallback& callback) { | 1446 const GetResourceListCallback& callback) { |
1620 if (offline_) { | 1447 if (offline_) { |
1621 base::MessageLoop::current()->PostTask( | 1448 base::MessageLoop::current()->PostTask( |
1622 FROM_HERE, | 1449 FROM_HERE, |
1623 base::Bind(callback, | 1450 base::Bind(callback, |
1624 GDATA_NO_CONNECTION, | 1451 GDATA_NO_CONNECTION, |
1625 base::Passed(scoped_ptr<ResourceList>()))); | 1452 base::Passed(scoped_ptr<ResourceList>()))); |
1626 return; | 1453 return; |
1627 } | 1454 } |
1628 | 1455 |
1629 scoped_ptr<ResourceList> resource_list = | |
1630 ResourceList::CreateFrom(*resource_list_value_); | |
1631 | |
1632 // TODO(hashimoto): Drive API always provides largest changestamp. Remove this | |
1633 // if-statement after API switch. | |
1634 if (start_changestamp > 0 && start_offset == 0) | |
1635 resource_list->set_largest_changestamp(largest_changestamp_); | |
1636 | |
1637 // Filter out entries per parameters like |directory_resource_id| and | 1456 // Filter out entries per parameters like |directory_resource_id| and |
1638 // |search_query|. | 1457 // |search_query|. |
1639 ScopedVector<ResourceEntry>* entries = resource_list->mutable_entries(); | 1458 ScopedVector<ResourceEntry> entries; |
1640 | |
1641 int num_entries_matched = 0; | 1459 int num_entries_matched = 0; |
1642 for (size_t i = 0; i < entries->size();) { | 1460 for (EntryInfoMap::iterator it = entries_.begin(); it != entries_.end(); |
1643 ResourceEntry* entry = (*entries)[i]; | 1461 ++it) { |
| 1462 scoped_ptr<ResourceEntry> entry = |
| 1463 util::ConvertChangeResourceToResourceEntry(it->second->change_resource); |
1644 bool should_exclude = false; | 1464 bool should_exclude = false; |
1645 | 1465 |
1646 // If |directory_resource_id| is set, exclude the entry if it's not in | 1466 // If |directory_resource_id| is set, exclude the entry if it's not in |
1647 // the target directory. | 1467 // the target directory. |
1648 if (!directory_resource_id.empty()) { | 1468 if (!directory_resource_id.empty()) { |
1649 // Get the parent resource ID of the entry. | 1469 // Get the parent resource ID of the entry. |
1650 std::string parent_resource_id; | 1470 std::string parent_resource_id; |
1651 const google_apis::Link* parent_link = | 1471 const google_apis::Link* parent_link = |
1652 entry->GetLinkByType(Link::LINK_PARENT); | 1472 entry->GetLinkByType(Link::LINK_PARENT); |
1653 if (parent_link) { | 1473 if (parent_link) { |
(...skipping 27 matching lines...) Expand all Loading... |
1681 // The entry matched the criteria for inclusion. | 1501 // The entry matched the criteria for inclusion. |
1682 if (!should_exclude) | 1502 if (!should_exclude) |
1683 ++num_entries_matched; | 1503 ++num_entries_matched; |
1684 | 1504 |
1685 // If |start_offset| is set, exclude the entry if the entry is before the | 1505 // If |start_offset| is set, exclude the entry if the entry is before the |
1686 // start index. <= instead of < as |num_entries_matched| was | 1506 // start index. <= instead of < as |num_entries_matched| was |
1687 // already incremented. | 1507 // already incremented. |
1688 if (start_offset > 0 && num_entries_matched <= start_offset) | 1508 if (start_offset > 0 && num_entries_matched <= start_offset) |
1689 should_exclude = true; | 1509 should_exclude = true; |
1690 | 1510 |
1691 if (should_exclude) | 1511 if (!should_exclude) |
1692 entries->erase(entries->begin() + i); | 1512 entries.push_back(entry.release()); |
1693 else | |
1694 ++i; | |
1695 } | 1513 } |
1696 | 1514 |
| 1515 scoped_ptr<ResourceList> resource_list(new ResourceList); |
| 1516 if (start_changestamp > 0 && start_offset == 0) |
| 1517 resource_list->set_largest_changestamp(largest_changestamp_); |
| 1518 |
1697 // If |max_results| is set, trim the entries if the number exceeded the max | 1519 // If |max_results| is set, trim the entries if the number exceeded the max |
1698 // results. | 1520 // results. |
1699 if (max_results > 0 && entries->size() > static_cast<size_t>(max_results)) { | 1521 if (max_results > 0 && entries.size() > static_cast<size_t>(max_results)) { |
1700 entries->erase(entries->begin() + max_results, entries->end()); | 1522 entries.erase(entries.begin() + max_results, entries.end()); |
1701 // Adds the next URL. | 1523 // Adds the next URL. |
1702 // Here, we embed information which is needed for continuing the | 1524 // Here, we embed information which is needed for continuing the |
1703 // GetResourceList request in the next invocation into url query | 1525 // GetResourceList request in the next invocation into url query |
1704 // parameters. | 1526 // parameters. |
1705 GURL next_url(base::StringPrintf( | 1527 GURL next_url(base::StringPrintf( |
1706 "http://localhost/?start-offset=%d&max-results=%d", | 1528 "http://localhost/?start-offset=%d&max-results=%d", |
1707 start_offset + max_results, | 1529 start_offset + max_results, |
1708 max_results)); | 1530 max_results)); |
1709 if (start_changestamp > 0) { | 1531 if (start_changestamp > 0) { |
1710 next_url = net::AppendOrReplaceQueryParameter( | 1532 next_url = net::AppendOrReplaceQueryParameter( |
1711 next_url, "changestamp", | 1533 next_url, "changestamp", |
1712 base::Int64ToString(start_changestamp).c_str()); | 1534 base::Int64ToString(start_changestamp).c_str()); |
1713 } | 1535 } |
1714 if (!search_query.empty()) { | 1536 if (!search_query.empty()) { |
1715 next_url = net::AppendOrReplaceQueryParameter( | 1537 next_url = net::AppendOrReplaceQueryParameter( |
1716 next_url, "q", search_query); | 1538 next_url, "q", search_query); |
1717 } | 1539 } |
1718 if (!directory_resource_id.empty()) { | 1540 if (!directory_resource_id.empty()) { |
1719 next_url = net::AppendOrReplaceQueryParameter( | 1541 next_url = net::AppendOrReplaceQueryParameter( |
1720 next_url, "parent", directory_resource_id); | 1542 next_url, "parent", directory_resource_id); |
1721 } | 1543 } |
1722 | 1544 |
1723 Link* link = new Link; | 1545 Link* link = new Link; |
1724 link->set_type(Link::LINK_NEXT); | 1546 link->set_type(Link::LINK_NEXT); |
1725 link->set_href(next_url); | 1547 link->set_href(next_url); |
1726 resource_list->mutable_links()->push_back(link); | 1548 resource_list->mutable_links()->push_back(link); |
1727 } | 1549 } |
| 1550 resource_list->set_entries(entries.Pass()); |
1728 | 1551 |
1729 if (load_counter) | 1552 if (load_counter) |
1730 *load_counter += 1; | 1553 *load_counter += 1; |
1731 base::MessageLoop::current()->PostTask( | 1554 base::MessageLoop::current()->PostTask( |
1732 FROM_HERE, | 1555 FROM_HERE, |
1733 base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_list))); | 1556 base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_list))); |
1734 } | 1557 } |
1735 | 1558 |
1736 GURL FakeDriveService::GetNewUploadSessionUrl() { | 1559 GURL FakeDriveService::GetNewUploadSessionUrl() { |
1737 return GURL("https://upload_session_url/" + | 1560 return GURL("https://upload_session_url/" + |
1738 base::Int64ToString(next_upload_sequence_number_++)); | 1561 base::Int64ToString(next_upload_sequence_number_++)); |
1739 } | 1562 } |
1740 | 1563 |
1741 } // namespace drive | 1564 } // namespace drive |
OLD | NEW |