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 |