15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chrome/browser/supervised_user/supervised_user_shared_settings_service.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/json/json_reader.h"
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/json/json_writer.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/prefs/pref_service.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/prefs/scoped_user_pref_update.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/values.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/common/pref_names.h"
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/pref_registry/pref_registry_syncable.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "sync/api/sync_change.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "sync/api/sync_data.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "sync/api/sync_error.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "sync/api/sync_error_factory.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "sync/api/sync_merge_result.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "sync/protocol/sync.pb.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using base::DictionaryValue;
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using base::Value;
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using syncer::ModelType;
24116680a4aac90f2aa7413d9095a592090648e557Ben Murdochusing syncer::SUPERVISED_USER_SHARED_SETTINGS;
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using syncer::SyncChange;
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using syncer::SyncChangeList;
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using syncer::SyncChangeProcessor;
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using syncer::SyncData;
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using syncer::SyncDataList;
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using syncer::SyncError;
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using syncer::SyncErrorFactory;
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using syncer::SyncMergeResult;
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kAcknowledged[] = "acknowledged";
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kValue[] = "value";
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DictionaryValue* FindOrCreateDictionary(DictionaryValue* parent,
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        const std::string& key) {
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DictionaryValue* dict = NULL;
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!parent->GetDictionaryWithoutPathExpansion(key, &dict)) {
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    dict = new DictionaryValue;
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    parent->SetWithoutPathExpansion(key, dict);
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return dict;
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class ScopedSupervisedUserSharedSettingsUpdate {
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ScopedSupervisedUserSharedSettingsUpdate(PrefService* prefs,
52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                           const std::string& su_id)
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      : update_(prefs, prefs::kSupervisedUserSharedSettings), su_id_(su_id) {
54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    DCHECK(!su_id.empty());
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // A supervised user can only modify their own settings.
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::string id = prefs->GetString(prefs::kSupervisedUserId);
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    DCHECK(id.empty() || id == su_id);
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DictionaryValue* Get() {
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return FindOrCreateDictionary(update_.Get(), su_id_);
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DictionaryPrefUpdate update_;
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::string su_id_;
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SyncData CreateSyncDataForValue(
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& su_id,
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& key,
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const Value& dict_value) {
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const DictionaryValue* dict = NULL;
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!dict_value.GetAsDictionary(&dict))
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return SyncData();
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const Value* value = NULL;
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!dict->Get(kValue, &value))
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return SyncData();
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool acknowledged = false;
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  dict->GetBoolean(kAcknowledged, &acknowledged);
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return SupervisedUserSharedSettingsService::CreateSyncDataForSetting(
86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      su_id, key, *value, acknowledged);
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SupervisedUserSharedSettingsService::SupervisedUserSharedSettingsService(
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PrefService* prefs)
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : prefs_(prefs) {}
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SupervisedUserSharedSettingsService::~SupervisedUserSharedSettingsService() {}
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSharedSettingsService::SetValueInternal(
99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& su_id,
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& key,
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const Value& value,
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool acknowledged) {
103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ScopedSupervisedUserSharedSettingsUpdate update(prefs_, su_id);
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DictionaryValue* update_dict = update.Get();
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DictionaryValue* dict = NULL;
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool has_key = update_dict->GetDictionaryWithoutPathExpansion(key, &dict);
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!has_key) {
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    dict = new DictionaryValue;
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    update_dict->SetWithoutPathExpansion(key, dict);
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  dict->SetWithoutPathExpansion(kValue, value.DeepCopy());
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  dict->SetBooleanWithoutPathExpansion(kAcknowledged, acknowledged);
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!sync_processor_)
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  SyncData data = CreateSyncDataForSetting(su_id, key, value, acknowledged);
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SyncChange::SyncChangeType change_type =
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      has_key ? SyncChange::ACTION_UPDATE : SyncChange::ACTION_ADD;
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SyncChangeList changes;
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  changes.push_back(SyncChange(FROM_HERE, change_type, data));
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!error.IsSet()) << error.ToString();
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const Value* SupervisedUserSharedSettingsService::GetValue(
128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& su_id,
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& key) {
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const DictionaryValue* data =
131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      prefs_->GetDictionary(prefs::kSupervisedUserSharedSettings);
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const DictionaryValue* dict = NULL;
133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!data->GetDictionaryWithoutPathExpansion(su_id, &dict))
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return NULL;
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const DictionaryValue* settings = NULL;
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!dict->GetDictionaryWithoutPathExpansion(key, &settings))
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return NULL;
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const Value* value = NULL;
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!settings->GetWithoutPathExpansion(kValue, &value))
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return NULL;
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return value;
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSharedSettingsService::SetValue(
148f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& su_id,
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& key,
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const Value& value) {
151f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  SetValueInternal(su_id, key, value, true);
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
154f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)scoped_ptr<
155f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    SupervisedUserSharedSettingsService::ChangeCallbackList::Subscription>
156f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SupervisedUserSharedSettingsService::Subscribe(
157f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const SupervisedUserSharedSettingsService::ChangeCallback& cb) {
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return callbacks_.Add(cb);
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSharedSettingsService::RegisterProfilePrefs(
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    user_prefs::PrefRegistrySyncable* registry) {
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  registry->RegisterDictionaryPref(
165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      prefs::kSupervisedUserSharedSettings,
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SyncData SupervisedUserSharedSettingsService::CreateSyncDataForSetting(
171f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& su_id,
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& key,
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const Value& value,
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool acknowledged) {
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string json_value;
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::JSONWriter::Write(&value, &json_value);
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ::sync_pb::EntitySpecifics specifics;
178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  specifics.mutable_managed_user_shared_setting()->set_mu_id(su_id);
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  specifics.mutable_managed_user_shared_setting()->set_key(key);
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  specifics.mutable_managed_user_shared_setting()->set_value(json_value);
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  specifics.mutable_managed_user_shared_setting()->set_acknowledged(
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      acknowledged);
183f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::string title = su_id + ":" + key;
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return SyncData::CreateLocalData(title, title, specifics);
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSharedSettingsService::Shutdown() {}
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)syncer::SyncMergeResult
190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SupervisedUserSharedSettingsService::MergeDataAndStartSyncing(
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    syncer::ModelType type,
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const syncer::SyncDataList& initial_sync_data,
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<syncer::SyncErrorFactory> error_handler) {
195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, type);
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  sync_processor_ = sync_processor.Pass();
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  error_handler_ = error_handler.Pass();
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // We keep a map from MU ID to the set of keys that we have seen in the
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // initial sync data.
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::map<std::string, std::set<std::string> > seen_keys;
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Iterate over all initial sync data, and update it locally. This means that
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the value from the server always wins over a local value.
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (SyncDataList::const_iterator it = initial_sync_data.begin();
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != initial_sync_data.end();
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++it) {
208f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, it->GetDataType());
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ::sync_pb::ManagedUserSharedSettingSpecifics&
210f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        supervised_user_shared_setting =
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            it->GetSpecifics().managed_user_shared_setting();
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<Value> value(
213f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        base::JSONReader::Read(supervised_user_shared_setting.value()));
214f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& su_id = supervised_user_shared_setting.mu_id();
215f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ScopedSupervisedUserSharedSettingsUpdate update(prefs_, su_id);
216f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& key = supervised_user_shared_setting.key();
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DictionaryValue* dict = FindOrCreateDictionary(update.Get(), key);
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    dict->SetWithoutPathExpansion(kValue, value.release());
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Every setting we get from the server should have the acknowledged flag
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // set.
222f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    DCHECK(supervised_user_shared_setting.acknowledged());
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    dict->SetBooleanWithoutPathExpansion(
224f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        kAcknowledged, supervised_user_shared_setting.acknowledged());
225f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    callbacks_.Notify(su_id, key);
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
227f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    seen_keys[su_id].insert(key);
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Iterate over all settings that we have locally, which includes settings
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // that were just synced down. We filter those out using |seen_keys|.
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SyncChangeList change_list;
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const DictionaryValue* all_settings =
234f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      prefs_->GetDictionary(prefs::kSupervisedUserSharedSettings);
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (DictionaryValue::Iterator it(*all_settings); !it.IsAtEnd();
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it.Advance()) {
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const DictionaryValue* dict = NULL;
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool success = it.value().GetAsDictionary(&dict);
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(success);
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::set<std::string>& seen = seen_keys[it.key()];
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (DictionaryValue::Iterator jt(*dict); !jt.IsAtEnd(); jt.Advance()) {
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // We only need to upload settings that we haven't seen in the initial
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // sync data (which means they were added locally).
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (seen.count(jt.key()) > 0)
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        continue;
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      SyncData data = CreateSyncDataForValue(it.key(), jt.key(), jt.value());
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DCHECK(data.IsValid());
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      change_list.push_back(
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          SyncChange(FROM_HERE, SyncChange::ACTION_ADD, data));
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
255f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  SyncMergeResult result(SUPERVISED_USER_SHARED_SETTINGS);
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Process all the accumulated changes.
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (change_list.size() > 0) {
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result.set_error(
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        sync_processor_->ProcessSyncChanges(FROM_HERE, change_list));
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(bauerb): Statistics?
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return result;
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
266f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserSharedSettingsService::StopSyncing(syncer::ModelType type) {
267f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, type);
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  sync_processor_.reset();
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  error_handler_.reset();
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
272f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)syncer::SyncDataList SupervisedUserSharedSettingsService::GetAllSyncData(
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    syncer::ModelType type) const {
274f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, type);
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SyncDataList data;
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const DictionaryValue* all_settings =
277f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      prefs_->GetDictionary(prefs::kSupervisedUserSharedSettings);
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (DictionaryValue::Iterator it(*all_settings); !it.IsAtEnd();
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it.Advance()) {
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const DictionaryValue* dict = NULL;
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool success = it.value().GetAsDictionary(&dict);
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(success);
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (DictionaryValue::Iterator jt(*dict); !jt.IsAtEnd(); jt.Advance()) {
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      data.push_back(CreateSyncDataForValue(it.key(), jt.key(), jt.value()));
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return data;
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
290f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)syncer::SyncError SupervisedUserSharedSettingsService::ProcessSyncChanges(
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const tracked_objects::Location& from_here,
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const syncer::SyncChangeList& change_list) {
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (SyncChangeList::const_iterator it = change_list.begin();
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != change_list.end();
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++it) {
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SyncData data = it->sync_data();
297f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, data.GetDataType());
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ::sync_pb::ManagedUserSharedSettingSpecifics&
299f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        supervised_user_shared_setting =
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            data.GetSpecifics().managed_user_shared_setting();
301f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& key = supervised_user_shared_setting.key();
302f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& su_id = supervised_user_shared_setting.mu_id();
303f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ScopedSupervisedUserSharedSettingsUpdate update(prefs_, su_id);
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DictionaryValue* update_dict = update.Get();
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DictionaryValue* dict = NULL;
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool has_key = update_dict->GetDictionaryWithoutPathExpansion(key, &dict);
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    switch (it->change_type()) {
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      case SyncChange::ACTION_ADD:
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      case SyncChange::ACTION_UPDATE: {
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // Every setting we get from the server should have the acknowledged
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // flag set.
312f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        DCHECK(supervised_user_shared_setting.acknowledged());
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (has_key) {
315f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          // If the supervised user already exists, it should be an update
316f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          // action.
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          DCHECK_EQ(SyncChange::ACTION_UPDATE, it->change_type());
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        } else {
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          // Otherwise, it should be an add action.
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          DCHECK_EQ(SyncChange::ACTION_ADD, it->change_type());
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          dict = new DictionaryValue;
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          update_dict->SetWithoutPathExpansion(key, dict);
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        scoped_ptr<Value> value(
325f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            base::JSONReader::Read(supervised_user_shared_setting.value()));
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        dict->SetWithoutPathExpansion(kValue, value.release());
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        dict->SetBooleanWithoutPathExpansion(
328f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            kAcknowledged, supervised_user_shared_setting.acknowledged());
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        break;
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      case SyncChange::ACTION_DELETE: {
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (has_key)
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          update_dict->RemoveWithoutPathExpansion(key, NULL);
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        else
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NOTREACHED() << "Trying to delete nonexistent key " << key;
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        break;
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      case SyncChange::ACTION_INVALID: {
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        NOTREACHED();
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        break;
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
343f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    callbacks_.Notify(su_id, key);
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SyncError error;
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return error;
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
349