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/ui/webui/options/managed_user_import_handler.h"
6
7#include <set>
8
9#include "base/bind.h"
10#include "base/prefs/pref_service.h"
11#include "base/values.h"
12#include "chrome/browser/browser_process.h"
13#include "chrome/browser/profiles/profile.h"
14#include "chrome/browser/profiles/profile_avatar_icon_util.h"
15#include "chrome/browser/profiles/profile_info_cache.h"
16#include "chrome/browser/profiles/profile_manager.h"
17#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
18#include "chrome/browser/signin/signin_manager_factory.h"
19#include "chrome/browser/supervised_user/supervised_user_constants.h"
20#include "chrome/browser/supervised_user/supervised_user_shared_settings_service.h"
21#include "chrome/browser/supervised_user/supervised_user_shared_settings_service_factory.h"
22#include "chrome/browser/supervised_user/supervised_user_sync_service.h"
23#include "chrome/browser/supervised_user/supervised_user_sync_service_factory.h"
24#include "chrome/common/pref_names.h"
25#include "chrome/common/url_constants.h"
26#include "components/signin/core/browser/profile_oauth2_token_service.h"
27#include "components/signin/core/browser/signin_error_controller.h"
28#include "components/signin/core/browser/signin_manager.h"
29#include "content/public/browser/web_ui.h"
30#include "grit/generated_resources.h"
31#include "grit/theme_resources.h"
32#include "ui/base/l10n/l10n_util.h"
33
34namespace {
35
36scoped_ptr<base::ListValue> GetAvatarIcons() {
37  scoped_ptr<base::ListValue> avatar_icons(new base::ListValue);
38  for (size_t i = 0; i < profiles::GetDefaultAvatarIconCount(); ++i) {
39    std::string avatar_url = profiles::GetDefaultAvatarIconUrl(i);
40    avatar_icons->Append(new base::StringValue(avatar_url));
41  }
42
43  return avatar_icons.Pass();
44}
45
46}  // namespace
47
48namespace options {
49
50ManagedUserImportHandler::ManagedUserImportHandler()
51    : observer_(this),
52      weak_ptr_factory_(this) {}
53
54ManagedUserImportHandler::~ManagedUserImportHandler() {
55  Profile* profile = Profile::FromWebUI(web_ui());
56  if (!profile->IsSupervised()) {
57    SupervisedUserSyncService* service =
58        SupervisedUserSyncServiceFactory::GetForProfile(profile);
59    if (service)
60      service->RemoveObserver(this);
61    subscription_.reset();
62  }
63}
64
65void ManagedUserImportHandler::GetLocalizedValues(
66    base::DictionaryValue* localized_strings) {
67  DCHECK(localized_strings);
68
69  static OptionsStringResource resources[] = {
70      { "managedUserImportTitle", IDS_IMPORT_EXISTING_MANAGED_USER_TITLE },
71      { "managedUserImportText", IDS_IMPORT_EXISTING_MANAGED_USER_TEXT },
72      { "createNewUserLink", IDS_CREATE_NEW_USER_LINK },
73      { "managedUserImportOk", IDS_IMPORT_EXISTING_MANAGED_USER_OK },
74      { "managedUserImportSigninError", IDS_MANAGED_USER_IMPORT_SIGN_IN_ERROR },
75      { "managedUserAlreadyOnThisDevice",
76          IDS_MANAGED_USER_ALREADY_ON_THIS_DEVICE },
77      { "noExistingManagedUsers", IDS_MANAGED_USER_NO_EXISTING_ERROR },
78      { "managedUserSelectAvatarTitle", IDS_MANAGED_USER_SELECT_AVATAR_TITLE },
79      { "managedUserSelectAvatarText", IDS_MANAGED_USER_SELECT_AVATAR_TEXT },
80      { "managedUserSelectAvatarOk", IDS_MANAGED_USER_SELECT_AVATAR_OK },
81  };
82
83  RegisterStrings(localized_strings, resources, arraysize(resources));
84  localized_strings->Set("avatarIcons", GetAvatarIcons().release());
85}
86
87void ManagedUserImportHandler::InitializeHandler() {
88  Profile* profile = Profile::FromWebUI(web_ui());
89  if (!profile->IsSupervised()) {
90    SupervisedUserSyncService* sync_service =
91        SupervisedUserSyncServiceFactory::GetForProfile(profile);
92    if (sync_service) {
93      sync_service->AddObserver(this);
94      observer_.Add(ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->
95                        signin_error_controller());
96      SupervisedUserSharedSettingsService* settings_service =
97          SupervisedUserSharedSettingsServiceFactory::GetForBrowserContext(
98              profile);
99      subscription_ = settings_service->Subscribe(
100          base::Bind(&ManagedUserImportHandler::OnSharedSettingChanged,
101                     weak_ptr_factory_.GetWeakPtr()));
102    } else {
103      DCHECK(!SupervisedUserSharedSettingsServiceFactory::GetForBrowserContext(
104                 profile));
105      DCHECK(!ProfileOAuth2TokenServiceFactory::GetForProfile(profile));
106    }
107  }
108}
109
110void ManagedUserImportHandler::RegisterMessages() {
111  web_ui()->RegisterMessageCallback("requestManagedUserImportUpdate",
112      base::Bind(&ManagedUserImportHandler::RequestManagedUserImportUpdate,
113                 base::Unretained(this)));
114}
115
116void ManagedUserImportHandler::OnSupervisedUsersChanged() {
117  FetchManagedUsers();
118}
119
120void ManagedUserImportHandler::FetchManagedUsers() {
121  web_ui()->CallJavascriptFunction("options.ManagedUserListData.resetPromise");
122  RequestManagedUserImportUpdate(NULL);
123}
124
125void ManagedUserImportHandler::RequestManagedUserImportUpdate(
126    const base::ListValue* /* args */) {
127  if (Profile::FromWebUI(web_ui())->IsSupervised())
128    return;
129
130  if (!IsAccountConnected() || HasAuthError()) {
131    ClearManagedUsersAndShowError();
132  } else {
133    SupervisedUserSyncService* supervised_user_sync_service =
134        SupervisedUserSyncServiceFactory::GetForProfile(
135            Profile::FromWebUI(web_ui()));
136    if (supervised_user_sync_service) {
137      supervised_user_sync_service->GetSupervisedUsersAsync(
138          base::Bind(&ManagedUserImportHandler::SendExistingManagedUsers,
139                     weak_ptr_factory_.GetWeakPtr()));
140    }
141  }
142}
143
144void ManagedUserImportHandler::SendExistingManagedUsers(
145    const base::DictionaryValue* dict) {
146  DCHECK(dict);
147  const ProfileInfoCache& cache =
148      g_browser_process->profile_manager()->GetProfileInfoCache();
149
150  // Collect the ids of local supervised user profiles.
151  std::set<std::string> supervised_user_ids;
152  for (size_t i = 0; i < cache.GetNumberOfProfiles(); ++i) {
153    if (cache.ProfileIsSupervisedAtIndex(i))
154      supervised_user_ids.insert(cache.GetSupervisedUserIdOfProfileAtIndex(i));
155  }
156
157  base::ListValue supervised_users;
158  Profile* profile = Profile::FromWebUI(web_ui());
159  SupervisedUserSharedSettingsService* service =
160      SupervisedUserSharedSettingsServiceFactory::GetForBrowserContext(profile);
161  for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
162    const base::DictionaryValue* value = NULL;
163    bool success = it.value().GetAsDictionary(&value);
164    DCHECK(success);
165    std::string name;
166    value->GetString(SupervisedUserSyncService::kName, &name);
167
168    base::DictionaryValue* supervised_user = new base::DictionaryValue;
169    supervised_user->SetString("id", it.key());
170    supervised_user->SetString("name", name);
171
172    int avatar_index = SupervisedUserSyncService::kNoAvatar;
173    const base::Value* avatar_index_value =
174        service->GetValue(it.key(), supervised_users::kChromeAvatarIndex);
175    if (avatar_index_value) {
176      success = avatar_index_value->GetAsInteger(&avatar_index);
177    } else {
178      // Check if there is a legacy avatar index stored.
179      std::string avatar_str;
180      value->GetString(SupervisedUserSyncService::kChromeAvatar, &avatar_str);
181      success =
182          SupervisedUserSyncService::GetAvatarIndex(avatar_str, &avatar_index);
183    }
184    DCHECK(success);
185    supervised_user->SetBoolean(
186        "needAvatar",
187        avatar_index == SupervisedUserSyncService::kNoAvatar);
188
189    std::string supervised_user_icon =
190        std::string(chrome::kChromeUIThemeURL) +
191        "IDR_SUPERVISED_USER_PLACEHOLDER";
192    std::string avatar_url =
193        avatar_index == SupervisedUserSyncService::kNoAvatar ?
194            supervised_user_icon :
195            profiles::GetDefaultAvatarIconUrl(avatar_index);
196    supervised_user->SetString("iconURL", avatar_url);
197    bool on_current_device =
198        supervised_user_ids.find(it.key()) != supervised_user_ids.end();
199    supervised_user->SetBoolean("onCurrentDevice", on_current_device);
200
201    supervised_users.Append(supervised_user);
202  }
203
204  web_ui()->CallJavascriptFunction(
205      "options.ManagedUserListData.receiveExistingManagedUsers",
206      supervised_users);
207}
208
209void ManagedUserImportHandler::ClearManagedUsersAndShowError() {
210  web_ui()->CallJavascriptFunction("options.ManagedUserListData.onSigninError");
211}
212
213bool ManagedUserImportHandler::IsAccountConnected() const {
214  Profile* profile = Profile::FromWebUI(web_ui());
215  SigninManagerBase* signin_manager =
216      SigninManagerFactory::GetForProfile(profile);
217  return signin_manager && !signin_manager->GetAuthenticatedUsername().empty();
218}
219
220bool ManagedUserImportHandler::HasAuthError() const {
221  Profile* profile = Profile::FromWebUI(web_ui());
222  ProfileOAuth2TokenService* token_service =
223      ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
224  if (!token_service)
225    return true;
226
227  SigninErrorController* error_controller =
228      token_service->signin_error_controller();
229
230  GoogleServiceAuthError::State state = error_controller->auth_error().state();
231
232  return state == GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS ||
233      state == GoogleServiceAuthError::USER_NOT_SIGNED_UP ||
234      state == GoogleServiceAuthError::ACCOUNT_DELETED ||
235      state == GoogleServiceAuthError::ACCOUNT_DISABLED;
236}
237
238void ManagedUserImportHandler::OnSharedSettingChanged(
239    const std::string& supervised_user_id,
240    const std::string& key) {
241  if (key == supervised_users::kChromeAvatarIndex)
242    FetchManagedUsers();
243}
244
245void ManagedUserImportHandler::OnErrorChanged() {
246  FetchManagedUsers();
247}
248
249}  // namespace options
250