chromium/chrome/browser/ui/webui/ash/settings/pages/files/one_drive_page_handler.cc

// Copyright 2023 The Chromium Authors
// 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/ash/settings/pages/files/one_drive_page_handler.h"

#include <optional>

#include "ash/webui/system_apps/public/system_web_app_type.h"
#include "chrome/browser/ash/file_manager/open_util.h"
#include "chrome/browser/ash/file_system_provider/mount_path_util.h"
#include "chrome/browser/ash/file_system_provider/provided_file_system_info.h"
#include "chrome/browser/ash/file_system_provider/provided_file_system_interface.h"
#include "chrome/browser/ash/file_system_provider/service.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h"
#include "chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_util.h"
#include "chrome/browser/ui/webui/ash/settings/pages/files/mojom/one_drive_handler.mojom.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/pref_names.h"

namespace ash::settings {

namespace {
void OnGetEmailAddress(
    OneDrivePageHandler::GetUserEmailAddressCallback callback,
    base::expected<cloud_upload::ODFSMetadata, base::File::Error>
        metadata_or_error) {
  if (!metadata_or_error.has_value()) {
    LOG(ERROR) << "Failed to get user email: " << metadata_or_error.error();
    std::move(callback).Run(std::nullopt);
    return;
  }
  if (metadata_or_error->user_email.empty()) {
    LOG(ERROR) << "User email is empty";
    std::move(callback).Run(std::nullopt);
    return;
  }
  std::move(callback).Run(metadata_or_error->user_email);
}

void OnShowItemInFolder(
    OneDrivePageHandler::OpenOneDriveFolderCallback callback,
    platform_util::OpenOperationResult result) {
  std::move(callback).Run(result ==
                          platform_util::OpenOperationResult::OPEN_SUCCEEDED);
}
}  // namespace

OneDrivePageHandler::OneDrivePageHandler(
    mojo::PendingReceiver<one_drive::mojom::PageHandler> receiver,
    mojo::PendingRemote<one_drive::mojom::Page> page,
    Profile* profile)
    : profile_(profile),
      pref_change_registrar_(std::make_unique<PrefChangeRegistrar>()),
      page_(std::move(page)),
      receiver_(this, std::move(receiver)) {
  file_system_provider::Service* service =
      file_system_provider::Service::Get(profile_);
  if (service) {
    service->AddObserver(this);
  }

  pref_change_registrar_->Init(profile_->GetPrefs());
  pref_change_registrar_->Add(
      prefs::kAllowUserToRemoveODFS,
      base::BindRepeating(&OneDrivePageHandler::OnAllowUserToRemoveODFSChanged,
                          base::Unretained(this)));
  OnAllowUserToRemoveODFSChanged();
}

OneDrivePageHandler::~OneDrivePageHandler() {
  file_system_provider::Service* service =
      file_system_provider::Service::Get(profile_);
  if (service) {
    service->RemoveObserver(this);
  }
}

void OneDrivePageHandler::GetUserEmailAddress(
    GetUserEmailAddressCallback callback) {
  file_system_provider::ProvidedFileSystemInterface* file_system =
      cloud_upload::GetODFS(profile_);
  if (!file_system) {
    std::move(callback).Run(std::nullopt);
    return;
  }
  cloud_upload::GetODFSMetadata(
      file_system, base::BindOnce(&OnGetEmailAddress, std::move(callback)));
}

void OneDrivePageHandler::ConnectToOneDrive(
    ConnectToOneDriveCallback callback) {
  std::optional<file_system_provider::ProvidedFileSystemInfo>
      odfs_file_system_info = cloud_upload::GetODFSInfo(profile_);
  if (odfs_file_system_info.has_value()) {
    LOG(ERROR) << "ODFS already mounted";
    std::move(callback).Run(false);
    return;
  }
  // Show connect OneDrive dialog. This method's callback is called before the
  // user tries to sign in. The connection status is detected separately by
  // listening to provided file system mount events.
  Browser* browser =
      FindSystemWebAppBrowser(profile_, ash::SystemWebAppType::FILE_MANAGER);
  gfx::NativeWindow modal_parent =
      browser ? browser->window()->GetNativeWindow() : nullptr;
  std::move(callback).Run(
      ash::cloud_upload::ShowConnectOneDriveDialog(modal_parent));
}

void OneDrivePageHandler::DisconnectFromOneDrive(
    DisconnectFromOneDriveCallback callback) {
  std::optional<file_system_provider::ProvidedFileSystemInfo> file_system =
      cloud_upload::GetODFSInfo(profile_);
  if (!file_system) {
    LOG(ERROR) << "ODFS not found";
    std::move(callback).Run(false);
    return;
  }
  auto* service = file_system_provider::Service::Get(profile_);
  std::move(callback).Run(service->RequestUnmount(
      file_system->provider_id(), file_system->file_system_id()));
}

void OneDrivePageHandler::OpenOneDriveFolder(
    OpenOneDriveFolderCallback callback) {
  std::optional<file_system_provider::ProvidedFileSystemInfo> file_system =
      cloud_upload::GetODFSInfo(profile_);
  if (!file_system) {
    LOG(ERROR) << "ODFS not found";
    std::move(callback).Run(false);
    return;
  }
  file_manager::util::ShowItemInFolder(
      profile_, file_system->mount_path(),
      base::BindOnce(&OnShowItemInFolder, std::move(callback)));
}

void OneDrivePageHandler::OnProvidedFileSystemMount(
    const ash::file_system_provider::ProvidedFileSystemInfo& file_system_info,
    ash::file_system_provider::MountContext context,
    base::File::Error error) {
  file_system_provider::ProviderId odfs_provider_id =
      file_system_provider::ProviderId::CreateFromExtensionId(
          extension_misc::kODFSExtensionId);
  // Only observe successful mount events for ODFS.
  if (file_system_info.provider_id() != odfs_provider_id ||
      error != base::File::FILE_OK) {
    return;
  }
  page_->OnODFSMountOrUnmount();
}

void OneDrivePageHandler::OnProvidedFileSystemUnmount(
    const ash::file_system_provider::ProvidedFileSystemInfo& file_system_info,
    base::File::Error error) {
  file_system_provider::ProviderId odfs_provider_id =
      file_system_provider::ProviderId::CreateFromExtensionId(
          extension_misc::kODFSExtensionId);
  // Only observe successful unmount events for ODFS.
  if (file_system_info.provider_id() != odfs_provider_id ||
      error != base::File::FILE_OK) {
    return;
  }
  page_->OnODFSMountOrUnmount();
}

void OneDrivePageHandler::OnAllowUserToRemoveODFSChanged() {
  std::optional<file_system_provider::ProvidedFileSystemInfo> file_system =
      cloud_upload::GetODFSInfo(profile_);
  if (!file_system) {
    return;
  }
  const PrefService* pref_service = profile_->GetPrefs();
  page_->OnAllowUserToRemoveODFSChanged(
      pref_service->GetBoolean(prefs::kAllowUserToRemoveODFS));
}

}  // namespace ash::settings