Add an UMA stat to be able to see if the User pods are show on start screen,
[chromium-blink-merge.git] / components / enhanced_bookmarks / bookmark_server_cluster_service.cc
blobe433717a91eb978aae4934de4d39a7724c775c55
1 // Copyright 2014 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.
5 #include "components/enhanced_bookmarks/bookmark_server_cluster_service.h"
7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/values.h"
12 #include "components/bookmarks/browser/bookmark_model.h"
13 #include "components/enhanced_bookmarks/enhanced_bookmark_model.h"
14 #include "components/enhanced_bookmarks/enhanced_bookmark_utils.h"
15 #include "components/enhanced_bookmarks/pref_names.h"
16 #include "components/enhanced_bookmarks/proto/cluster.pb.h"
17 #include "components/pref_registry/pref_registry_syncable.h"
18 #include "components/signin/core/browser/signin_manager.h"
19 #include "net/base/url_util.h"
20 #include "net/url_request/url_fetcher.h"
21 #include "net/url_request/url_request_context_getter.h"
23 using bookmarks::BookmarkNode;
25 namespace {
26 const char kClusterUrl[] = "https://www.google.com/stars/cluster";
27 const int kPrefServiceVersion = 1;
28 const char kPrefServiceVersionKey[] = "version";
29 const char kPrefServiceDataKey[] = "data";
30 const char kAuthIdKey[] = "auth_id";
31 } // namespace
33 namespace enhanced_bookmarks {
35 BookmarkServerClusterService::BookmarkServerClusterService(
36 const std::string& application_language_code,
37 scoped_refptr<net::URLRequestContextGetter> request_context_getter,
38 ProfileOAuth2TokenService* token_service,
39 SigninManagerBase* signin_manager,
40 enhanced_bookmarks::EnhancedBookmarkModel* enhanced_bookmark_model,
41 PrefService* pref_service)
42 : BookmarkServerService(request_context_getter,
43 token_service,
44 signin_manager,
45 enhanced_bookmark_model),
46 application_language_code_(application_language_code),
47 pref_service_(pref_service) {
48 LoadModel();
50 if (model_->loaded())
51 TriggerTokenRequest(false);
53 GetSigninManager()->AddObserver(this);
56 BookmarkServerClusterService::~BookmarkServerClusterService() {
57 GetSigninManager()->RemoveObserver(this);
60 const std::vector<const BookmarkNode*>
61 BookmarkServerClusterService::BookmarksForClusterNamed(
62 const std::string& cluster_name) const {
63 std::vector<const BookmarkNode*> results;
65 ClusterMap::const_iterator cluster_it = cluster_data_.find(cluster_name);
66 if (cluster_it == cluster_data_.end())
67 return results;
69 for (auto& star_id : cluster_it->second) {
70 const BookmarkNode* bookmark = BookmarkForRemoteId(star_id);
71 if (bookmark)
72 results.push_back(bookmark);
74 return results;
77 const std::vector<std::string>
78 BookmarkServerClusterService::ClustersForBookmark(
79 const BookmarkNode* bookmark) const {
80 const std::string& star_id = RemoteIDForBookmark(bookmark);
82 // TODO(noyau): if this turns out to be a perf bottleneck this may be improved
83 // by storing a reverse map from id to cluster.
84 std::vector<std::string> clusters;
85 for (auto& pair : cluster_data_) {
86 const std::vector<std::string>& stars_ids = pair.second;
87 if (std::find(stars_ids.begin(), stars_ids.end(), star_id) !=
88 stars_ids.end())
89 clusters.push_back(pair.first);
91 return clusters;
94 const std::vector<std::string> BookmarkServerClusterService::GetClusters()
95 const {
96 std::vector<std::string> cluster_names;
98 for (auto& pair : cluster_data_) {
99 for (auto& star_id : pair.second) {
100 const BookmarkNode* bookmark = BookmarkForRemoteId(star_id);
101 if (bookmark) {
102 // Only add clusters that have children.
103 cluster_names.push_back(pair.first);
104 break;
109 return cluster_names;
112 // static
113 void BookmarkServerClusterService::RegisterPrefs(
114 user_prefs::PrefRegistrySyncable* registry) {
115 registry->RegisterDictionaryPref(
116 prefs::kBookmarkClusters,
117 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
120 scoped_ptr<net::URLFetcher> BookmarkServerClusterService::CreateFetcher() {
121 // Add the necessary arguments to the URI.
122 GURL url(kClusterUrl);
123 url = net::AppendQueryParameter(url, "output", "proto");
125 // Append language.
126 if (!application_language_code_.empty())
127 url = net::AppendQueryParameter(url, "hl", application_language_code_);
129 url = net::AppendQueryParameter(url, "v", model_->GetVersionString());
131 // Build the URLFetcher to perform the request.
132 scoped_ptr<net::URLFetcher> url_fetcher(
133 net::URLFetcher::Create(url, net::URLFetcher::POST, this));
135 // Binary encode a basic request proto.
136 image_collections::ClusterRequest request_proto;
137 request_proto.set_cluster_all(true);
139 std::string proto_output;
140 bool result = request_proto.SerializePartialToString(&proto_output);
141 DCHECK(result);
143 url_fetcher->SetUploadData("application/octet-stream", proto_output);
144 return url_fetcher;
147 bool BookmarkServerClusterService::ProcessResponse(const std::string& response,
148 bool* should_notify) {
149 DCHECK(*should_notify);
150 image_collections::ClusterResponse response_proto;
151 bool result = response_proto.ParseFromString(response);
152 if (!result)
153 return false; // Not formatted properly.
155 ClusterMap new_cluster_data;
156 for (const auto& cluster : response_proto.clusters()) {
157 const std::string& title = cluster.title();
158 if (title.empty())
159 continue;
160 std::vector<std::string> stars_ids;
161 for (auto& doc : cluster.docs()) {
162 if (!doc.empty())
163 stars_ids.push_back(doc);
165 if (stars_ids.size())
166 new_cluster_data[title] = stars_ids;
169 if (new_cluster_data.size() == cluster_data_.size() &&
170 std::equal(new_cluster_data.begin(),
171 new_cluster_data.end(),
172 cluster_data_.begin())) {
173 *should_notify = false;
174 } else {
175 SwapModel(&new_cluster_data);
177 return true;
180 void BookmarkServerClusterService::CleanAfterFailure() {
181 if (cluster_data_.empty())
182 return;
184 ClusterMap empty;
185 SwapModel(&empty);
188 void BookmarkServerClusterService::EnhancedBookmarkModelLoaded() {
189 TriggerTokenRequest(false);
192 void BookmarkServerClusterService::EnhancedBookmarkAdded(
193 const BookmarkNode* node) {
194 // Nothing to do.
197 void BookmarkServerClusterService::EnhancedBookmarkRemoved(
198 const BookmarkNode* node) {
199 // It is possible to remove the entries from the map here, but as those are
200 // filtered in ClustersForBookmark() this is not strictly necessary.
203 void BookmarkServerClusterService::EnhancedBookmarkNodeChanged(
204 const BookmarkNode* node) {
205 // Nothing to do.
208 void BookmarkServerClusterService::EnhancedBookmarkAllUserNodesRemoved() {
209 if (!cluster_data_.empty()) {
210 ClusterMap empty;
211 SwapModel(&empty);
215 void BookmarkServerClusterService::EnhancedBookmarkRemoteIdChanged(
216 const BookmarkNode* node,
217 const std::string& old_remote_id,
218 const std::string& remote_id) {
219 std::vector<std::string> clusters;
220 for (auto& pair : cluster_data_) {
221 std::vector<std::string>& stars_ids = pair.second;
222 std::replace(stars_ids.begin(), stars_ids.end(), old_remote_id, remote_id);
226 void BookmarkServerClusterService::GoogleSignedOut(
227 const std::string& account_id,
228 const std::string& username) {
229 if (!cluster_data_.empty()) {
230 ClusterMap empty;
231 SwapModel(&empty);
235 void BookmarkServerClusterService::SwapModel(ClusterMap* cluster_map) {
236 cluster_data_.swap(*cluster_map);
237 const std::string& auth_id = GetSigninManager()->GetAuthenticatedAccountId();
238 scoped_ptr<base::DictionaryValue> dictionary(
239 Serialize(cluster_data_, auth_id));
240 pref_service_->Set(prefs::kBookmarkClusters, *dictionary);
243 void BookmarkServerClusterService::LoadModel() {
244 const base::DictionaryValue* dictionary =
245 pref_service_->GetDictionary(prefs::kBookmarkClusters);
246 const std::string& auth_id = GetSigninManager()->GetAuthenticatedAccountId();
248 ClusterMap loaded_data;
249 bool result = BookmarkServerClusterService::Deserialize(
250 *dictionary, auth_id, &loaded_data);
251 if (result)
252 cluster_data_.swap(loaded_data);
256 // Serialization.
258 // static
259 scoped_ptr<base::DictionaryValue> BookmarkServerClusterService::Serialize(
260 const ClusterMap& cluster_map,
261 const std::string& auth_id) {
262 // Create a list of all clusters. For each cluster, make another list. The
263 // first element in the list is the key (cluster name). All subsequent
264 // elements are stars ids.
265 scoped_ptr<base::ListValue> all_clusters(new base::ListValue);
266 for (auto& pair : cluster_map) {
267 scoped_ptr<base::ListValue> cluster(new base::ListValue);
268 cluster->AppendString(pair.first);
269 cluster->AppendStrings(pair.second);
270 all_clusters->Append(cluster.release());
273 // The dictionary that will be serialized has two fields: a version field and
274 // a data field.
275 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue);
276 data->SetInteger(kPrefServiceVersionKey, kPrefServiceVersion);
277 data->Set(kPrefServiceDataKey, all_clusters.release());
278 data->SetString(kAuthIdKey, auth_id);
280 return data.Pass();
283 // static
284 bool BookmarkServerClusterService::Deserialize(
285 const base::DictionaryValue& value,
286 const std::string& auth_id,
287 ClusterMap* out_map) {
288 ClusterMap output;
290 // Check version.
291 int version;
292 if (!value.GetInteger(kPrefServiceVersionKey, &version))
293 return false;
294 if (version != kPrefServiceVersion)
295 return false;
297 // Check auth id.
298 std::string id;
299 if (!value.GetString(kAuthIdKey, &id))
300 return false;
301 if (id != auth_id)
302 return false;
304 const base::ListValue* all_clusters = NULL;
305 if (!value.GetList(kPrefServiceDataKey, &all_clusters))
306 return false;
308 for (size_t index = 0; index < all_clusters->GetSize(); ++index) {
309 const base::ListValue* cluster = NULL;
310 if (!all_clusters->GetList(index, &cluster))
311 return false;
312 if (cluster->GetSize() < 1)
313 return false;
314 std::string key;
315 if (!cluster->GetString(0, &key))
316 return false;
317 std::vector<std::string> stars_ids;
318 for (size_t index = 1; index < cluster->GetSize(); ++index) {
319 std::string stars_id;
320 if (!cluster->GetString(index, &stars_id))
321 return false;
322 stars_ids.push_back(stars_id);
324 output.insert(std::make_pair(key, stars_ids));
326 out_map->swap(output);
327 return true;
330 } // namespace enhanced_bookmarks