Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/managed_mode/managed_user_shared_settings_service.h" | |
| 6 | |
| 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/user_prefs/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" | |
| 20 | |
| 21 using base::DictionaryValue; | |
| 22 using base::Value; | |
| 23 using syncer::MANAGED_USER_SHARED_SETTINGS; | |
| 24 using syncer::ModelType; | |
| 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; | |
| 33 | |
| 34 namespace { | |
| 35 | |
| 36 const char kAcknowledged[] = "acknowledged"; | |
| 37 const char kValue[] = "value"; | |
| 38 | |
| 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); | |
| 45 } | |
| 46 return dict; | |
| 47 } | |
| 48 | |
| 49 class ScopedManagedUserSharedSettingsUpdate { | |
| 50 public: | |
| 51 ScopedManagedUserSharedSettingsUpdate(PrefService* prefs, | |
| 52 const std::string& mu_id) | |
| 53 : update_(prefs, prefs::kManagedUserSharedSettings), mu_id_(mu_id) { | |
| 54 // A supervised user can only modify their own settings. | |
| 55 std::string id = prefs->GetString(prefs::kManagedUserId); | |
| 56 DCHECK(id.empty() || id == mu_id); | |
|
Pam (message me for reviews)
2014/01/08 10:30:40
Suggest also checking that the mu_id is not empty.
Bernhard Bauer
2014/01/08 11:42:04
Done.
| |
| 57 } | |
| 58 | |
| 59 DictionaryValue* Get() { | |
| 60 return FindOrCreateDictionary(update_.Get(), mu_id_); | |
| 61 } | |
| 62 | |
| 63 private: | |
| 64 DictionaryPrefUpdate update_; | |
| 65 std::string mu_id_; | |
| 66 }; | |
| 67 | |
| 68 SyncData CreateSyncDataForValue( | |
| 69 const std::string& mu_id, | |
| 70 const std::string& key, | |
| 71 const Value& dict_value) { | |
| 72 const DictionaryValue* dict = NULL; | |
| 73 if (!dict_value.GetAsDictionary(&dict)) | |
| 74 return SyncData(); | |
| 75 | |
| 76 const Value* value = NULL; | |
| 77 if (!dict->Get(kValue, &value)) | |
| 78 return SyncData(); | |
| 79 | |
| 80 bool acknowledged = false; | |
| 81 dict->GetBoolean(kAcknowledged, &acknowledged); | |
| 82 | |
| 83 return ManagedUserSharedSettingsService::CreateSyncDataForSetting( | |
| 84 mu_id, key, *value, acknowledged); | |
| 85 } | |
| 86 | |
| 87 } // namespace | |
| 88 | |
| 89 | |
| 90 ManagedUserSharedSettingsService::ManagedUserSharedSettingsService( | |
| 91 PrefService* prefs) | |
| 92 : prefs_(prefs) {} | |
| 93 | |
| 94 ManagedUserSharedSettingsService::~ManagedUserSharedSettingsService() {} | |
| 95 | |
| 96 void ManagedUserSharedSettingsService::SetValueInternal( | |
| 97 const std::string& mu_id, | |
| 98 const std::string& key, | |
| 99 const Value& value, | |
| 100 bool acknowledged) { | |
| 101 ScopedManagedUserSharedSettingsUpdate update(prefs_, mu_id); | |
| 102 DictionaryValue* update_dict = update.Get(); | |
| 103 | |
| 104 DictionaryValue* dict = NULL; | |
| 105 bool has_key = update_dict->GetDictionaryWithoutPathExpansion(key, &dict); | |
| 106 if (!has_key) { | |
| 107 dict = new DictionaryValue; | |
| 108 update_dict->SetWithoutPathExpansion(key, dict); | |
| 109 } | |
| 110 dict->SetWithoutPathExpansion(kValue, value.DeepCopy()); | |
| 111 dict->SetBooleanWithoutPathExpansion(kAcknowledged, acknowledged); | |
| 112 | |
| 113 if (!sync_processor_) | |
| 114 return; | |
| 115 | |
| 116 SyncData data = CreateSyncDataForSetting(mu_id, key, value, acknowledged); | |
| 117 SyncChange::SyncChangeType change_type = | |
| 118 has_key ? SyncChange::ACTION_UPDATE : SyncChange::ACTION_ADD; | |
| 119 SyncChangeList changes; | |
| 120 changes.push_back(SyncChange(FROM_HERE, change_type, data)); | |
| 121 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, changes); | |
| 122 DCHECK(!error.IsSet()) << error.ToString(); | |
| 123 } | |
| 124 | |
| 125 const Value* ManagedUserSharedSettingsService::GetValue( | |
| 126 const std::string& mu_id, | |
| 127 const std::string& key) { | |
| 128 const DictionaryValue* data = | |
| 129 prefs_->GetDictionary(prefs::kManagedUserSharedSettings); | |
| 130 const DictionaryValue* dict = NULL; | |
| 131 if (!data->GetDictionaryWithoutPathExpansion(mu_id, &dict)) | |
|
Pam (message me for reviews)
2014/01/08 10:30:40
It would be worth documenting these three nested d
Bernhard Bauer
2014/01/08 11:42:04
Done.
| |
| 132 return NULL; | |
| 133 | |
| 134 const DictionaryValue* settings = NULL; | |
| 135 if (!dict->GetDictionaryWithoutPathExpansion(key, &settings)) | |
| 136 return NULL; | |
| 137 | |
| 138 const Value* value = NULL; | |
| 139 if (!settings->GetWithoutPathExpansion(kValue, &value)) | |
| 140 return NULL; | |
| 141 | |
| 142 return value; | |
| 143 } | |
| 144 | |
| 145 void ManagedUserSharedSettingsService::SetValue( | |
| 146 const std::string& mu_id, | |
| 147 const std::string& key, | |
| 148 const Value& value) { | |
| 149 SetValueInternal(mu_id, key, value, true); | |
| 150 } | |
| 151 | |
| 152 scoped_ptr<ManagedUserSharedSettingsService::CallbackList::Subscription> | |
| 153 ManagedUserSharedSettingsService::Subscribe( | |
| 154 const ManagedUserSharedSettingsService::Callback& cb) { | |
| 155 return callbacks_.Add(cb); | |
| 156 } | |
| 157 | |
| 158 // static | |
| 159 void ManagedUserSharedSettingsService::RegisterProfilePrefs( | |
| 160 user_prefs::PrefRegistrySyncable* registry) { | |
| 161 registry->RegisterDictionaryPref( | |
| 162 prefs::kManagedUserSharedSettings, | |
| 163 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | |
| 164 } | |
| 165 | |
| 166 // static | |
| 167 SyncData ManagedUserSharedSettingsService::CreateSyncDataForSetting( | |
| 168 const std::string& mu_id, | |
| 169 const std::string& key, | |
| 170 const Value& value, | |
| 171 bool acknowledged) { | |
| 172 std::string json_value; | |
| 173 base::JSONWriter::Write(&value, &json_value); | |
| 174 ::sync_pb::EntitySpecifics specifics; | |
| 175 specifics.mutable_managed_user_shared_setting()->set_mu_id(mu_id); | |
| 176 specifics.mutable_managed_user_shared_setting()->set_key(key); | |
| 177 specifics.mutable_managed_user_shared_setting()->set_value(json_value); | |
| 178 specifics.mutable_managed_user_shared_setting()->set_acknowledged( | |
| 179 acknowledged); | |
| 180 std::string title = mu_id + ":" + key; | |
| 181 return SyncData::CreateLocalData(title, title, specifics); | |
| 182 } | |
| 183 | |
| 184 void ManagedUserSharedSettingsService::Shutdown() {} | |
| 185 | |
| 186 syncer::SyncMergeResult | |
| 187 ManagedUserSharedSettingsService::MergeDataAndStartSyncing( | |
| 188 syncer::ModelType type, | |
| 189 const syncer::SyncDataList& initial_sync_data, | |
| 190 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, | |
| 191 scoped_ptr<syncer::SyncErrorFactory> error_handler) { | |
| 192 DCHECK_EQ(MANAGED_USER_SHARED_SETTINGS, type); | |
| 193 sync_processor_ = sync_processor.Pass(); | |
| 194 error_handler_ = error_handler.Pass(); | |
| 195 | |
| 196 std::map<std::string, std::set<std::string> > seen_keys; | |
|
Pam (message me for reviews)
2014/01/08 10:30:40
How 'bout some inline comments?
Bernhard Bauer
2014/01/08 11:42:04
Done.
| |
| 197 for (SyncDataList::const_iterator it = initial_sync_data.begin(); | |
| 198 it != initial_sync_data.end(); | |
| 199 ++it) { | |
| 200 DCHECK_EQ(MANAGED_USER_SHARED_SETTINGS, it->GetDataType()); | |
| 201 const ::sync_pb::ManagedUserSharedSettingSpecifics& | |
| 202 managed_user_shared_setting = | |
| 203 it->GetSpecifics().managed_user_shared_setting(); | |
| 204 scoped_ptr<Value> value( | |
| 205 base::JSONReader::Read(managed_user_shared_setting.value())); | |
| 206 const std::string& mu_id = managed_user_shared_setting.mu_id(); | |
| 207 ScopedManagedUserSharedSettingsUpdate update(prefs_, mu_id); | |
| 208 const std::string& key = managed_user_shared_setting.key(); | |
| 209 DictionaryValue* dict = FindOrCreateDictionary(update.Get(), key); | |
| 210 dict->SetWithoutPathExpansion(kValue, value.release()); | |
| 211 DCHECK(managed_user_shared_setting.acknowledged()); | |
| 212 dict->SetBooleanWithoutPathExpansion( | |
| 213 kAcknowledged, managed_user_shared_setting.acknowledged()); | |
| 214 callbacks_.Notify(mu_id, key); | |
| 215 | |
| 216 seen_keys[mu_id].insert(key); | |
| 217 } | |
| 218 | |
| 219 SyncChangeList change_list; | |
| 220 const DictionaryValue* all_settings = | |
| 221 prefs_->GetDictionary(prefs::kManagedUserSharedSettings); | |
| 222 for (DictionaryValue::Iterator it(*all_settings); !it.IsAtEnd(); | |
| 223 it.Advance()) { | |
| 224 const DictionaryValue* dict = NULL; | |
| 225 bool success = it.value().GetAsDictionary(&dict); | |
| 226 DCHECK(success); | |
| 227 | |
| 228 const std::set<std::string>& seen = seen_keys[it.key()]; | |
| 229 for (DictionaryValue::Iterator jt(*dict); !jt.IsAtEnd(); jt.Advance()) { | |
| 230 if (seen.count(jt.key()) > 0) | |
| 231 continue; | |
| 232 | |
| 233 SyncData data = CreateSyncDataForValue(it.key(), jt.key(), jt.value()); | |
| 234 DCHECK(data.IsValid()); | |
| 235 change_list.push_back( | |
| 236 SyncChange(FROM_HERE, SyncChange::ACTION_ADD, data)); | |
| 237 } | |
| 238 } | |
| 239 | |
| 240 SyncMergeResult result(MANAGED_USER_SHARED_SETTINGS); | |
| 241 // Process all the accumulated changes. | |
| 242 if (change_list.size() > 0) { | |
| 243 result.set_error( | |
| 244 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list)); | |
| 245 } | |
| 246 | |
| 247 // TODO(bauerb): Statistics? | |
| 248 return result; | |
| 249 } | |
| 250 | |
| 251 void ManagedUserSharedSettingsService::StopSyncing(syncer::ModelType type) { | |
| 252 DCHECK_EQ(MANAGED_USER_SHARED_SETTINGS, type); | |
| 253 sync_processor_.reset(); | |
| 254 error_handler_.reset(); | |
| 255 } | |
| 256 | |
| 257 syncer::SyncDataList ManagedUserSharedSettingsService::GetAllSyncData( | |
| 258 syncer::ModelType type) const { | |
| 259 DCHECK_EQ(MANAGED_USER_SHARED_SETTINGS, type); | |
| 260 SyncDataList data; | |
| 261 const DictionaryValue* all_settings = | |
| 262 prefs_->GetDictionary(prefs::kManagedUserSharedSettings); | |
| 263 for (DictionaryValue::Iterator it(*all_settings); !it.IsAtEnd(); | |
| 264 it.Advance()) { | |
| 265 const DictionaryValue* dict = NULL; | |
| 266 bool success = it.value().GetAsDictionary(&dict); | |
| 267 DCHECK(success); | |
| 268 for (DictionaryValue::Iterator jt(*dict); !jt.IsAtEnd(); jt.Advance()) { | |
| 269 data.push_back(CreateSyncDataForValue(it.key(), jt.key(), jt.value())); | |
| 270 } | |
| 271 } | |
| 272 return data; | |
| 273 } | |
| 274 | |
| 275 syncer::SyncError ManagedUserSharedSettingsService::ProcessSyncChanges( | |
| 276 const tracked_objects::Location& from_here, | |
| 277 const syncer::SyncChangeList& change_list) { | |
| 278 for (SyncChangeList::const_iterator it = change_list.begin(); | |
| 279 it != change_list.end(); | |
| 280 ++it) { | |
| 281 SyncData data = it->sync_data(); | |
| 282 DCHECK_EQ(MANAGED_USER_SHARED_SETTINGS, data.GetDataType()); | |
| 283 const ::sync_pb::ManagedUserSharedSettingSpecifics& | |
| 284 managed_user_shared_setting = | |
| 285 data.GetSpecifics().managed_user_shared_setting(); | |
| 286 const std::string& key = managed_user_shared_setting.key(); | |
| 287 const std::string& mu_id = managed_user_shared_setting.mu_id(); | |
| 288 ScopedManagedUserSharedSettingsUpdate update(prefs_, mu_id); | |
| 289 DictionaryValue* update_dict = update.Get(); | |
| 290 DictionaryValue* dict = NULL; | |
| 291 bool has_key = update_dict->GetDictionaryWithoutPathExpansion(key, &dict); | |
| 292 switch (it->change_type()) { | |
| 293 case SyncChange::ACTION_ADD: | |
| 294 case SyncChange::ACTION_UPDATE: { | |
| 295 if (has_key) { | |
| 296 // For an update action, the managed user should already exist. | |
|
Pam (message me for reviews)
2014/01/08 10:30:40
This comment is backwards from the logic; i.e., it
Bernhard Bauer
2014/01/08 11:42:04
It's a sanity check to make sure that the copy of
| |
| 297 DCHECK_EQ(SyncChange::ACTION_UPDATE, it->change_type()); | |
| 298 } else { | |
| 299 // For an add action, it should not. | |
| 300 DCHECK_EQ(SyncChange::ACTION_ADD, it->change_type()); | |
| 301 dict = new DictionaryValue; | |
| 302 update_dict->SetWithoutPathExpansion(key, dict); | |
| 303 } | |
| 304 scoped_ptr<Value> value( | |
| 305 base::JSONReader::Read(managed_user_shared_setting.value())); | |
| 306 dict->SetWithoutPathExpansion(kValue, value.release()); | |
| 307 dict->SetBooleanWithoutPathExpansion( | |
| 308 kAcknowledged, managed_user_shared_setting.acknowledged()); | |
| 309 break; | |
| 310 } | |
| 311 case SyncChange::ACTION_DELETE: { | |
| 312 if (has_key) | |
| 313 update_dict->RemoveWithoutPathExpansion(key, NULL); | |
| 314 else | |
| 315 NOTREACHED() << "Trying to delete nonexistent key " << key; | |
| 316 break; | |
| 317 } | |
| 318 case SyncChange::ACTION_INVALID: { | |
| 319 NOTREACHED(); | |
| 320 break; | |
| 321 } | |
| 322 } | |
| 323 callbacks_.Notify(mu_id, key); | |
| 324 } | |
| 325 | |
| 326 SyncError error; | |
| 327 return error; | |
| 328 } | |
| OLD | NEW |