Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / chrome / browser / supervised_user / supervised_user_shared_settings_service.cc
blobaf23c0a7f6ab016561fe996d2620668f954fa988
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 "chrome/browser/supervised_user/supervised_user_shared_settings_service.h"
7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/prefs/scoped_user_pref_update.h"
11 #include "base/values.h"
12 #include "chrome/common/pref_names.h"
13 #include "components/pref_registry/pref_registry_syncable.h"
14 #include "sync/api/sync_change.h"
15 #include "sync/api/sync_data.h"
16 #include "sync/api/sync_error.h"
17 #include "sync/api/sync_error_factory.h"
18 #include "sync/api/sync_merge_result.h"
19 #include "sync/protocol/sync.pb.h"
21 using base::DictionaryValue;
22 using base::Value;
23 using syncer::ModelType;
24 using syncer::SUPERVISED_USER_SHARED_SETTINGS;
25 using syncer::SyncChange;
26 using syncer::SyncChangeList;
27 using syncer::SyncChangeProcessor;
28 using syncer::SyncData;
29 using syncer::SyncDataList;
30 using syncer::SyncError;
31 using syncer::SyncErrorFactory;
32 using syncer::SyncMergeResult;
34 namespace {
36 const char kAcknowledged[] = "acknowledged";
37 const char kValue[] = "value";
39 DictionaryValue* FindOrCreateDictionary(DictionaryValue* parent,
40 const std::string& key) {
41 DictionaryValue* dict = NULL;
42 if (!parent->GetDictionaryWithoutPathExpansion(key, &dict)) {
43 dict = new DictionaryValue;
44 parent->SetWithoutPathExpansion(key, dict);
46 return dict;
49 class ScopedSupervisedUserSharedSettingsUpdate {
50 public:
51 ScopedSupervisedUserSharedSettingsUpdate(PrefService* prefs,
52 const std::string& su_id)
53 : update_(prefs, prefs::kSupervisedUserSharedSettings), su_id_(su_id) {
54 DCHECK(!su_id.empty());
56 // A supervised user can only modify their own settings.
57 std::string id = prefs->GetString(prefs::kSupervisedUserId);
58 DCHECK(id.empty() || id == su_id);
61 DictionaryValue* Get() {
62 return FindOrCreateDictionary(update_.Get(), su_id_);
65 private:
66 DictionaryPrefUpdate update_;
67 std::string su_id_;
70 SyncData CreateSyncDataForValue(
71 const std::string& su_id,
72 const std::string& key,
73 const Value& dict_value) {
74 const DictionaryValue* dict = NULL;
75 if (!dict_value.GetAsDictionary(&dict))
76 return SyncData();
78 const Value* value = NULL;
79 if (!dict->Get(kValue, &value))
80 return SyncData();
82 bool acknowledged = false;
83 dict->GetBoolean(kAcknowledged, &acknowledged);
85 return SupervisedUserSharedSettingsService::CreateSyncDataForSetting(
86 su_id, key, *value, acknowledged);
89 } // namespace
92 SupervisedUserSharedSettingsService::SupervisedUserSharedSettingsService(
93 PrefService* prefs)
94 : prefs_(prefs) {}
96 SupervisedUserSharedSettingsService::~SupervisedUserSharedSettingsService() {}
98 void SupervisedUserSharedSettingsService::SetValueInternal(
99 const std::string& su_id,
100 const std::string& key,
101 const Value& value,
102 bool acknowledged) {
103 ScopedSupervisedUserSharedSettingsUpdate update(prefs_, su_id);
104 DictionaryValue* update_dict = update.Get();
106 DictionaryValue* dict = NULL;
107 bool has_key = update_dict->GetDictionaryWithoutPathExpansion(key, &dict);
108 if (!has_key) {
109 dict = new DictionaryValue;
110 update_dict->SetWithoutPathExpansion(key, dict);
112 dict->SetWithoutPathExpansion(kValue, value.DeepCopy());
113 dict->SetBooleanWithoutPathExpansion(kAcknowledged, acknowledged);
115 if (!sync_processor_)
116 return;
118 SyncData data = CreateSyncDataForSetting(su_id, key, value, acknowledged);
119 SyncChange::SyncChangeType change_type =
120 has_key ? SyncChange::ACTION_UPDATE : SyncChange::ACTION_ADD;
121 SyncChangeList changes;
122 changes.push_back(SyncChange(FROM_HERE, change_type, data));
123 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
124 DCHECK(!error.IsSet()) << error.ToString();
127 const Value* SupervisedUserSharedSettingsService::GetValue(
128 const std::string& su_id,
129 const std::string& key) {
130 const DictionaryValue* data =
131 prefs_->GetDictionary(prefs::kSupervisedUserSharedSettings);
132 const DictionaryValue* dict = NULL;
133 if (!data->GetDictionaryWithoutPathExpansion(su_id, &dict))
134 return NULL;
136 const DictionaryValue* settings = NULL;
137 if (!dict->GetDictionaryWithoutPathExpansion(key, &settings))
138 return NULL;
140 const Value* value = NULL;
141 if (!settings->GetWithoutPathExpansion(kValue, &value))
142 return NULL;
144 return value;
147 void SupervisedUserSharedSettingsService::SetValue(
148 const std::string& su_id,
149 const std::string& key,
150 const Value& value) {
151 SetValueInternal(su_id, key, value, true);
154 scoped_ptr<
155 SupervisedUserSharedSettingsService::ChangeCallbackList::Subscription>
156 SupervisedUserSharedSettingsService::Subscribe(
157 const SupervisedUserSharedSettingsService::ChangeCallback& cb) {
158 return callbacks_.Add(cb);
161 // static
162 void SupervisedUserSharedSettingsService::RegisterProfilePrefs(
163 user_prefs::PrefRegistrySyncable* registry) {
164 registry->RegisterDictionaryPref(
165 prefs::kSupervisedUserSharedSettings,
166 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
169 // static
170 SyncData SupervisedUserSharedSettingsService::CreateSyncDataForSetting(
171 const std::string& su_id,
172 const std::string& key,
173 const Value& value,
174 bool acknowledged) {
175 std::string json_value;
176 base::JSONWriter::Write(&value, &json_value);
177 ::sync_pb::EntitySpecifics specifics;
178 specifics.mutable_managed_user_shared_setting()->set_mu_id(su_id);
179 specifics.mutable_managed_user_shared_setting()->set_key(key);
180 specifics.mutable_managed_user_shared_setting()->set_value(json_value);
181 specifics.mutable_managed_user_shared_setting()->set_acknowledged(
182 acknowledged);
183 std::string title = su_id + ":" + key;
184 return SyncData::CreateLocalData(title, title, specifics);
187 void SupervisedUserSharedSettingsService::Shutdown() {}
189 syncer::SyncMergeResult
190 SupervisedUserSharedSettingsService::MergeDataAndStartSyncing(
191 syncer::ModelType type,
192 const syncer::SyncDataList& initial_sync_data,
193 scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
194 scoped_ptr<syncer::SyncErrorFactory> error_handler) {
195 DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, type);
196 sync_processor_ = sync_processor.Pass();
197 error_handler_ = error_handler.Pass();
199 // We keep a map from MU ID to the set of keys that we have seen in the
200 // initial sync data.
201 std::map<std::string, std::set<std::string> > seen_keys;
203 // Iterate over all initial sync data, and update it locally. This means that
204 // the value from the server always wins over a local value.
205 for (SyncDataList::const_iterator it = initial_sync_data.begin();
206 it != initial_sync_data.end();
207 ++it) {
208 DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, it->GetDataType());
209 const ::sync_pb::ManagedUserSharedSettingSpecifics&
210 supervised_user_shared_setting =
211 it->GetSpecifics().managed_user_shared_setting();
212 scoped_ptr<Value> value(
213 base::JSONReader::Read(supervised_user_shared_setting.value()));
214 const std::string& su_id = supervised_user_shared_setting.mu_id();
215 ScopedSupervisedUserSharedSettingsUpdate update(prefs_, su_id);
216 const std::string& key = supervised_user_shared_setting.key();
217 DictionaryValue* dict = FindOrCreateDictionary(update.Get(), key);
218 dict->SetWithoutPathExpansion(kValue, value.release());
220 // Every setting we get from the server should have the acknowledged flag
221 // set.
222 DCHECK(supervised_user_shared_setting.acknowledged());
223 dict->SetBooleanWithoutPathExpansion(
224 kAcknowledged, supervised_user_shared_setting.acknowledged());
225 callbacks_.Notify(su_id, key);
227 seen_keys[su_id].insert(key);
230 // Iterate over all settings that we have locally, which includes settings
231 // that were just synced down. We filter those out using |seen_keys|.
232 SyncChangeList change_list;
233 const DictionaryValue* all_settings =
234 prefs_->GetDictionary(prefs::kSupervisedUserSharedSettings);
235 for (DictionaryValue::Iterator it(*all_settings); !it.IsAtEnd();
236 it.Advance()) {
237 const DictionaryValue* dict = NULL;
238 bool success = it.value().GetAsDictionary(&dict);
239 DCHECK(success);
241 const std::set<std::string>& seen = seen_keys[it.key()];
242 for (DictionaryValue::Iterator jt(*dict); !jt.IsAtEnd(); jt.Advance()) {
243 // We only need to upload settings that we haven't seen in the initial
244 // sync data (which means they were added locally).
245 if (seen.count(jt.key()) > 0)
246 continue;
248 SyncData data = CreateSyncDataForValue(it.key(), jt.key(), jt.value());
249 DCHECK(data.IsValid());
250 change_list.push_back(
251 SyncChange(FROM_HERE, SyncChange::ACTION_ADD, data));
255 SyncMergeResult result(SUPERVISED_USER_SHARED_SETTINGS);
256 // Process all the accumulated changes.
257 if (change_list.size() > 0) {
258 result.set_error(
259 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list));
262 // TODO(bauerb): Statistics?
263 return result;
266 void SupervisedUserSharedSettingsService::StopSyncing(syncer::ModelType type) {
267 DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, type);
268 sync_processor_.reset();
269 error_handler_.reset();
272 syncer::SyncDataList SupervisedUserSharedSettingsService::GetAllSyncData(
273 syncer::ModelType type) const {
274 DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, type);
275 SyncDataList data;
276 const DictionaryValue* all_settings =
277 prefs_->GetDictionary(prefs::kSupervisedUserSharedSettings);
278 for (DictionaryValue::Iterator it(*all_settings); !it.IsAtEnd();
279 it.Advance()) {
280 const DictionaryValue* dict = NULL;
281 bool success = it.value().GetAsDictionary(&dict);
282 DCHECK(success);
283 for (DictionaryValue::Iterator jt(*dict); !jt.IsAtEnd(); jt.Advance()) {
284 data.push_back(CreateSyncDataForValue(it.key(), jt.key(), jt.value()));
287 return data;
290 syncer::SyncError SupervisedUserSharedSettingsService::ProcessSyncChanges(
291 const tracked_objects::Location& from_here,
292 const syncer::SyncChangeList& change_list) {
293 for (SyncChangeList::const_iterator it = change_list.begin();
294 it != change_list.end();
295 ++it) {
296 SyncData data = it->sync_data();
297 DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, data.GetDataType());
298 const ::sync_pb::ManagedUserSharedSettingSpecifics&
299 supervised_user_shared_setting =
300 data.GetSpecifics().managed_user_shared_setting();
301 const std::string& key = supervised_user_shared_setting.key();
302 const std::string& su_id = supervised_user_shared_setting.mu_id();
303 ScopedSupervisedUserSharedSettingsUpdate update(prefs_, su_id);
304 DictionaryValue* update_dict = update.Get();
305 DictionaryValue* dict = NULL;
306 bool has_key = update_dict->GetDictionaryWithoutPathExpansion(key, &dict);
307 switch (it->change_type()) {
308 case SyncChange::ACTION_ADD:
309 case SyncChange::ACTION_UPDATE: {
310 // Every setting we get from the server should have the acknowledged
311 // flag set.
312 DCHECK(supervised_user_shared_setting.acknowledged());
314 if (has_key) {
315 // If the supervised user already exists, it should be an update
316 // action.
317 DCHECK_EQ(SyncChange::ACTION_UPDATE, it->change_type());
318 } else {
319 // Otherwise, it should be an add action.
320 DCHECK_EQ(SyncChange::ACTION_ADD, it->change_type());
321 dict = new DictionaryValue;
322 update_dict->SetWithoutPathExpansion(key, dict);
324 scoped_ptr<Value> value(
325 base::JSONReader::Read(supervised_user_shared_setting.value()));
326 dict->SetWithoutPathExpansion(kValue, value.release());
327 dict->SetBooleanWithoutPathExpansion(
328 kAcknowledged, supervised_user_shared_setting.acknowledged());
329 break;
331 case SyncChange::ACTION_DELETE: {
332 if (has_key)
333 update_dict->RemoveWithoutPathExpansion(key, NULL);
334 else
335 NOTREACHED() << "Trying to delete nonexistent key " << key;
336 break;
338 case SyncChange::ACTION_INVALID: {
339 NOTREACHED();
340 break;
343 callbacks_.Notify(su_id, key);
346 SyncError error;
347 return error;