Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / supervised_user / supervised_user_shared_settings_service.cc
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.
4
5 #include "chrome/browser/supervised_user/supervised_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/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"
20
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;
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 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());
55
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);
59   }
60
61   DictionaryValue* Get() {
62     return FindOrCreateDictionary(update_.Get(), su_id_);
63   }
64
65  private:
66   DictionaryPrefUpdate update_;
67   std::string su_id_;
68 };
69
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();
77
78   const Value* value = NULL;
79   if (!dict->Get(kValue, &value))
80     return SyncData();
81
82   bool acknowledged = false;
83   dict->GetBoolean(kAcknowledged, &acknowledged);
84
85   return SupervisedUserSharedSettingsService::CreateSyncDataForSetting(
86       su_id, key, *value, acknowledged);
87 }
88
89 }  // namespace
90
91
92 SupervisedUserSharedSettingsService::SupervisedUserSharedSettingsService(
93     PrefService* prefs)
94     : prefs_(prefs) {}
95
96 SupervisedUserSharedSettingsService::~SupervisedUserSharedSettingsService() {}
97
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();
105
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);
111   }
112   dict->SetWithoutPathExpansion(kValue, value.DeepCopy());
113   dict->SetBooleanWithoutPathExpansion(kAcknowledged, acknowledged);
114
115   if (!sync_processor_)
116     return;
117
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();
125 }
126
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;
135
136   const DictionaryValue* settings = NULL;
137   if (!dict->GetDictionaryWithoutPathExpansion(key, &settings))
138     return NULL;
139
140   const Value* value = NULL;
141   if (!settings->GetWithoutPathExpansion(kValue, &value))
142     return NULL;
143
144   return value;
145 }
146
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);
152 }
153
154 scoped_ptr<
155     SupervisedUserSharedSettingsService::ChangeCallbackList::Subscription>
156 SupervisedUserSharedSettingsService::Subscribe(
157     const SupervisedUserSharedSettingsService::ChangeCallback& cb) {
158   return callbacks_.Add(cb);
159 }
160
161 // static
162 void SupervisedUserSharedSettingsService::RegisterProfilePrefs(
163     user_prefs::PrefRegistrySyncable* registry) {
164   registry->RegisterDictionaryPref(
165       prefs::kSupervisedUserSharedSettings,
166       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
167 }
168
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);
185 }
186
187 void SupervisedUserSharedSettingsService::Shutdown() {}
188
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();
198
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;
202
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());
219
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);
226
227     seen_keys[su_id].insert(key);
228   }
229
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);
240
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;
247
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));
252     }
253   }
254
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));
260   }
261
262   // TODO(bauerb): Statistics?
263   return result;
264 }
265
266 void SupervisedUserSharedSettingsService::StopSyncing(syncer::ModelType type) {
267   DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, type);
268   sync_processor_.reset();
269   error_handler_.reset();
270 }
271
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()));
285     }
286   }
287   return data;
288 }
289
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());
313
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);
323         }
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;
330       }
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;
337       }
338       case SyncChange::ACTION_INVALID: {
339         NOTREACHED();
340         break;
341       }
342     }
343     callbacks_.Notify(su_id, key);
344   }
345
346   SyncError error;
347   return error;
348 }