| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/webui/options/supervised_user_import_handler.h" |
| |
| #include <stddef.h> |
| |
| #include <memory> |
| #include <set> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/macros.h" |
| #include "base/values.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/profiles/profile_attributes_entry.h" |
| #include "chrome/browser/profiles/profile_avatar_icon_util.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "chrome/browser/signin/signin_error_controller_factory.h" |
| #include "chrome/browser/signin/signin_manager_factory.h" |
| #include "chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service.h" |
| #include "chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service_factory.h" |
| #include "chrome/browser/supervised_user/legacy/supervised_user_sync_service.h" |
| #include "chrome/browser/supervised_user/legacy/supervised_user_sync_service_factory.h" |
| #include "chrome/browser/supervised_user/supervised_user_constants.h" |
| #include "chrome/common/url_constants.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "chrome/grit/theme_resources.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/signin/core/browser/signin_error_controller.h" |
| #include "components/signin/core/browser/signin_manager.h" |
| #include "content/public/browser/web_ui.h" |
| |
| namespace { |
| |
| std::unique_ptr<base::ListValue> GetAvatarIcons() { |
| std::unique_ptr<base::ListValue> avatar_icons(new base::ListValue); |
| for (size_t i = 0; i < profiles::GetDefaultAvatarIconCount(); ++i) { |
| std::string avatar_url = profiles::GetDefaultAvatarIconUrl(i); |
| avatar_icons->AppendString(avatar_url); |
| } |
| |
| return avatar_icons; |
| } |
| |
| bool ProfileIsLegacySupervised(const base::FilePath& profile_path) { |
| ProfileAttributesEntry* entry; |
| |
| return g_browser_process->profile_manager()->GetProfileAttributesStorage(). |
| GetProfileAttributesWithPath(profile_path, &entry) && |
| entry->IsLegacySupervised(); |
| } |
| |
| } // namespace |
| |
| namespace options { |
| |
| SupervisedUserImportHandler::SupervisedUserImportHandler() |
| : profile_observer_(this), |
| signin_error_observer_(this), |
| supervised_user_sync_service_observer_(this), |
| removed_profile_is_supervised_(false), |
| weak_ptr_factory_(this) { |
| } |
| |
| SupervisedUserImportHandler::~SupervisedUserImportHandler() { |
| } |
| |
| void SupervisedUserImportHandler::GetLocalizedValues( |
| base::DictionaryValue* localized_strings) { |
| DCHECK(localized_strings); |
| |
| static OptionsStringResource resources[] = { |
| { "supervisedUserImportTitle", |
| IDS_IMPORT_EXISTING_LEGACY_SUPERVISED_USER_TITLE }, |
| { "supervisedUserImportText", |
| IDS_IMPORT_EXISTING_LEGACY_SUPERVISED_USER_TEXT }, |
| { "createNewUserLink", IDS_CREATE_NEW_LEGACY_SUPERVISED_USER_LINK }, |
| { "supervisedUserImportOk", |
| IDS_IMPORT_EXISTING_LEGACY_SUPERVISED_USER_OK }, |
| { "supervisedUserImportSigninError", |
| IDS_LEGACY_SUPERVISED_USER_IMPORT_SIGN_IN_ERROR }, |
| { "supervisedUserAlreadyOnThisDevice", |
| IDS_LEGACY_SUPERVISED_USER_ALREADY_ON_THIS_DEVICE }, |
| { "noExistingSupervisedUsers", |
| IDS_LEGACY_SUPERVISED_USER_NO_EXISTING_ERROR }, |
| { "supervisedUserSelectAvatarTitle", |
| IDS_LEGACY_SUPERVISED_USER_SELECT_AVATAR_TITLE }, |
| { "supervisedUserSelectAvatarText", |
| IDS_LEGACY_SUPERVISED_USER_SELECT_AVATAR_TEXT }, |
| { "supervisedUserSelectAvatarOk", |
| IDS_LEGACY_SUPERVISED_USER_SELECT_AVATAR_OK }, |
| }; |
| |
| RegisterStrings(localized_strings, resources, arraysize(resources)); |
| localized_strings->Set("avatarIcons", GetAvatarIcons()); |
| } |
| |
| void SupervisedUserImportHandler::InitializeHandler() { |
| Profile* profile = Profile::FromWebUI(web_ui()); |
| if (!profile->IsSupervised()) { |
| profile_observer_.Add( |
| &g_browser_process->profile_manager()->GetProfileAttributesStorage()); |
| SupervisedUserSyncService* sync_service = |
| SupervisedUserSyncServiceFactory::GetForProfile(profile); |
| if (sync_service) { |
| supervised_user_sync_service_observer_.Add(sync_service); |
| signin_error_observer_.Add( |
| SigninErrorControllerFactory::GetForProfile(profile)); |
| SupervisedUserSharedSettingsService* settings_service = |
| SupervisedUserSharedSettingsServiceFactory::GetForBrowserContext( |
| profile); |
| subscription_ = settings_service->Subscribe( |
| base::Bind(&SupervisedUserImportHandler::OnSharedSettingChanged, |
| weak_ptr_factory_.GetWeakPtr())); |
| } else { |
| DCHECK(!SupervisedUserSharedSettingsServiceFactory::GetForBrowserContext( |
| profile)); |
| DCHECK(!SigninErrorControllerFactory::GetForProfile(profile)); |
| } |
| } |
| } |
| |
| void SupervisedUserImportHandler::RegisterMessages() { |
| web_ui()->RegisterMessageCallback("requestSupervisedUserImportUpdate", |
| base::Bind(&SupervisedUserImportHandler:: |
| RequestSupervisedUserImportUpdate, |
| base::Unretained(this))); |
| } |
| |
| void SupervisedUserImportHandler::OnProfileAdded( |
| const base::FilePath& profile_path) { |
| // When a supervised profile is added, re-send the list to update the |
| // the "already on this device" status. |
| if (ProfileIsLegacySupervised(profile_path)) |
| FetchSupervisedUsers(); |
| } |
| |
| void SupervisedUserImportHandler::OnProfileWillBeRemoved( |
| const base::FilePath& profile_path) { |
| DCHECK(!removed_profile_is_supervised_); |
| // When a supervised profile is removed, re-send the list to update the |
| // "already on this device" status. We can't do that right now because the |
| // profile still exists, so defer to OnProfileWasRemoved. |
| if (ProfileIsLegacySupervised(profile_path)) |
| removed_profile_is_supervised_ = true; |
| } |
| |
| void SupervisedUserImportHandler::OnProfileWasRemoved( |
| const base::FilePath& profile_path, |
| const base::string16& profile_name) { |
| if (removed_profile_is_supervised_) { |
| removed_profile_is_supervised_ = false; |
| FetchSupervisedUsers(); |
| } |
| } |
| |
| void SupervisedUserImportHandler::OnProfileIsOmittedChanged( |
| const base::FilePath& profile_path) { |
| if (ProfileIsLegacySupervised(profile_path)) |
| FetchSupervisedUsers(); |
| } |
| |
| void SupervisedUserImportHandler::OnSupervisedUsersChanged() { |
| FetchSupervisedUsers(); |
| } |
| |
| void SupervisedUserImportHandler::FetchSupervisedUsers() { |
| web_ui()->CallJavascriptFunctionUnsafe( |
| "options.SupervisedUserListData.resetPromise"); |
| RequestSupervisedUserImportUpdate(NULL); |
| } |
| |
| void SupervisedUserImportHandler::RequestSupervisedUserImportUpdate( |
| const base::ListValue* /* args */) { |
| if (Profile::FromWebUI(web_ui())->IsSupervised()) |
| return; |
| |
| if (!IsAccountConnected() || HasAuthError()) { |
| ClearSupervisedUsersAndShowError(); |
| } else { |
| SupervisedUserSyncService* supervised_user_sync_service = |
| SupervisedUserSyncServiceFactory::GetForProfile( |
| Profile::FromWebUI(web_ui())); |
| if (supervised_user_sync_service) { |
| supervised_user_sync_service->GetSupervisedUsersAsync( |
| base::Bind(&SupervisedUserImportHandler::SendExistingSupervisedUsers, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| } |
| } |
| |
| void SupervisedUserImportHandler::SendExistingSupervisedUsers( |
| const base::DictionaryValue* dict) { |
| DCHECK(dict); |
| std::vector<ProfileAttributesEntry*> entries = |
| g_browser_process->profile_manager()-> |
| GetProfileAttributesStorage().GetAllProfilesAttributes(); |
| |
| // Collect the ids of local supervised user profiles. |
| std::set<std::string> supervised_user_ids; |
| for (const ProfileAttributesEntry* entry : entries) { |
| // Filter out omitted profiles. These are currently being imported, and |
| // shouldn't show up as "already on this device" just yet. |
| if (entry->IsLegacySupervised() && !entry->IsOmitted()) { |
| supervised_user_ids.insert(entry->GetSupervisedUserId()); |
| } |
| } |
| |
| base::ListValue supervised_users; |
| Profile* profile = Profile::FromWebUI(web_ui()); |
| SupervisedUserSharedSettingsService* service = |
| SupervisedUserSharedSettingsServiceFactory::GetForBrowserContext(profile); |
| for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) { |
| const base::DictionaryValue* value = NULL; |
| bool success = it.value().GetAsDictionary(&value); |
| DCHECK(success); |
| std::string name; |
| value->GetString(SupervisedUserSyncService::kName, &name); |
| |
| std::unique_ptr<base::DictionaryValue> supervised_user( |
| new base::DictionaryValue); |
| supervised_user->SetString("id", it.key()); |
| supervised_user->SetString("name", name); |
| |
| int avatar_index = SupervisedUserSyncService::kNoAvatar; |
| const base::Value* avatar_index_value = |
| service->GetValue(it.key(), supervised_users::kChromeAvatarIndex); |
| if (avatar_index_value) { |
| success = avatar_index_value->GetAsInteger(&avatar_index); |
| } else { |
| // Check if there is a legacy avatar index stored. |
| std::string avatar_str; |
| value->GetString(SupervisedUserSyncService::kChromeAvatar, &avatar_str); |
| success = |
| SupervisedUserSyncService::GetAvatarIndex(avatar_str, &avatar_index); |
| } |
| DCHECK(success); |
| supervised_user->SetBoolean( |
| "needAvatar", |
| avatar_index == SupervisedUserSyncService::kNoAvatar); |
| |
| std::string supervised_user_icon = |
| std::string(chrome::kChromeUIThemeURL) + |
| "IDR_SUPERVISED_USER_PLACEHOLDER"; |
| std::string avatar_url = |
| avatar_index == SupervisedUserSyncService::kNoAvatar ? |
| supervised_user_icon : |
| profiles::GetDefaultAvatarIconUrl(avatar_index); |
| supervised_user->SetString("iconURL", avatar_url); |
| bool on_current_device = |
| supervised_user_ids.find(it.key()) != supervised_user_ids.end(); |
| supervised_user->SetBoolean("onCurrentDevice", on_current_device); |
| |
| supervised_users.Append(std::move(supervised_user)); |
| } |
| |
| web_ui()->CallJavascriptFunctionUnsafe( |
| "options.SupervisedUserListData.receiveExistingSupervisedUsers", |
| supervised_users); |
| } |
| |
| void SupervisedUserImportHandler::ClearSupervisedUsersAndShowError() { |
| web_ui()->CallJavascriptFunctionUnsafe( |
| "options.SupervisedUserListData.onSigninError"); |
| } |
| |
| bool SupervisedUserImportHandler::IsAccountConnected() const { |
| Profile* profile = Profile::FromWebUI(web_ui()); |
| SigninManagerBase* signin_manager = |
| SigninManagerFactory::GetForProfile(profile); |
| return signin_manager && signin_manager->IsAuthenticated(); |
| } |
| |
| bool SupervisedUserImportHandler::HasAuthError() const { |
| Profile* profile = Profile::FromWebUI(web_ui()); |
| SigninErrorController* error_controller = |
| SigninErrorControllerFactory::GetForProfile(profile); |
| if (!error_controller) |
| return true; |
| |
| GoogleServiceAuthError::State state = error_controller->auth_error().state(); |
| |
| return state == GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS || |
| state == GoogleServiceAuthError::USER_NOT_SIGNED_UP || |
| state == GoogleServiceAuthError::ACCOUNT_DELETED || |
| state == GoogleServiceAuthError::ACCOUNT_DISABLED; |
| } |
| |
| void SupervisedUserImportHandler::OnSharedSettingChanged( |
| const std::string& supervised_user_id, |
| const std::string& key) { |
| if (key == supervised_users::kChromeAvatarIndex) |
| FetchSupervisedUsers(); |
| } |
| |
| void SupervisedUserImportHandler::OnErrorChanged() { |
| FetchSupervisedUsers(); |
| } |
| |
| } // namespace options |