chromium/google_apis/tasks/tasks_api_requests.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 "google_apis/tasks/tasks_api_requests.h"

#include <memory>
#include <string>

#include "base/check.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/types/expected.h"
#include "base/values.h"
#include "google_apis/common/api_error_codes.h"
#include "google_apis/common/base_requests.h"
#include "google_apis/common/request_sender.h"
#include "google_apis/tasks/tasks_api_request_types.h"
#include "google_apis/tasks/tasks_api_response_types.h"
#include "google_apis/tasks/tasks_api_url_generator_utils.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "url/gurl.h"

namespace google_apis::tasks {
namespace {

constexpr char kContentTypeJson[] = "application/json; charset=utf-8";
constexpr int kMaxAllowedMaxResults = 100;

}

// ----- ListTaskListsRequest -----

ListTaskListsRequest::ListTaskListsRequest(RequestSender* sender,
                                           const std::string& page_token,
                                           Callback callback)
    : UrlFetchRequestBase(sender, ProgressCallback(), ProgressCallback()),
      page_token_(page_token),
      callback_(std::move(callback)) {
  CHECK(!callback_.is_null());
}

ListTaskListsRequest::~ListTaskListsRequest() = default;

GURL ListTaskListsRequest::GetURL() const {
  return GetListTaskListsUrl(kMaxAllowedMaxResults, page_token_);
}

ApiErrorCode ListTaskListsRequest::MapReasonToError(ApiErrorCode code,
                                                    const std::string& reason) {
  return code;
}

bool ListTaskListsRequest::IsSuccessfulErrorCode(ApiErrorCode error) {
  return error == HTTP_SUCCESS;
}

void ListTaskListsRequest::ProcessURLFetchResults(
    const network::mojom::URLResponseHead* response_head,
    base::FilePath response_file,
    std::string response_body) {
  ApiErrorCode error = GetErrorCode();
  switch (error) {
    case HTTP_SUCCESS:
      blocking_task_runner()->PostTaskAndReplyWithResult(
          FROM_HERE,
          base::BindOnce(&ListTaskListsRequest::Parse,
                         std::move(response_body)),
          base::BindOnce(&ListTaskListsRequest::OnDataParsed,
                         weak_ptr_factory_.GetWeakPtr()));
      break;
    default:
      RunCallbackOnPrematureFailure(error);
      OnProcessURLFetchResultsComplete();
      break;
  }
}

void ListTaskListsRequest::RunCallbackOnPrematureFailure(ApiErrorCode error) {
  std::move(callback_).Run(base::unexpected(error));
}

std::unique_ptr<TaskLists> ListTaskListsRequest::Parse(std::string json) {
  std::unique_ptr<base::Value> value = ParseJson(json);
  return value ? TaskLists::CreateFrom(*value) : nullptr;
}

void ListTaskListsRequest::OnDataParsed(std::unique_ptr<TaskLists> task_lists) {
  if (!task_lists) {
    std::move(callback_).Run(base::unexpected(PARSE_ERROR));
  } else {
    std::move(callback_).Run(std::move(task_lists));
  }
  OnProcessURLFetchResultsComplete();
}

// ----- ListTasksRequest -----

ListTasksRequest::ListTasksRequest(RequestSender* sender,
                                   const std::string& task_list_id,
                                   const std::string& page_token,
                                   bool include_assigned,
                                   Callback callback)
    : UrlFetchRequestBase(sender, ProgressCallback(), ProgressCallback()),
      task_list_id_(task_list_id),
      page_token_(page_token),
      include_assigned_(include_assigned),
      callback_(std::move(callback)) {
  CHECK(!callback_.is_null());
  CHECK(!task_list_id_.empty());
}

ListTasksRequest::~ListTasksRequest() = default;

GURL ListTasksRequest::GetURL() const {
  return GetListTasksUrl(task_list_id_, /*include_completed=*/false,
                         /*include_assigned=*/include_assigned_,
                         kMaxAllowedMaxResults, page_token_);
}

ApiErrorCode ListTasksRequest::MapReasonToError(ApiErrorCode code,
                                                const std::string& reason) {
  return code;
}

bool ListTasksRequest::IsSuccessfulErrorCode(ApiErrorCode error) {
  return error == HTTP_SUCCESS;
}

void ListTasksRequest::ProcessURLFetchResults(
    const network::mojom::URLResponseHead* response_head,
    base::FilePath response_file,
    std::string response_body) {
  ApiErrorCode error = GetErrorCode();
  switch (error) {
    case HTTP_SUCCESS:
      blocking_task_runner()->PostTaskAndReplyWithResult(
          FROM_HERE,
          base::BindOnce(&ListTasksRequest::Parse, std::move(response_body)),
          base::BindOnce(&ListTasksRequest::OnDataParsed,
                         weak_ptr_factory_.GetWeakPtr()));
      break;
    default:
      RunCallbackOnPrematureFailure(error);
      OnProcessURLFetchResultsComplete();
      break;
  }
}

void ListTasksRequest::RunCallbackOnPrematureFailure(ApiErrorCode error) {
  std::move(callback_).Run(base::unexpected(error));
}

std::unique_ptr<Tasks> ListTasksRequest::Parse(std::string json) {
  std::unique_ptr<base::Value> value = ParseJson(json);
  return value ? Tasks::CreateFrom(*value) : nullptr;
}

void ListTasksRequest::OnDataParsed(std::unique_ptr<Tasks> tasks) {
  if (!tasks) {
    std::move(callback_).Run(base::unexpected(PARSE_ERROR));
  } else {
    std::move(callback_).Run(std::move(tasks));
  }
  OnProcessURLFetchResultsComplete();
}

// ----- PatchTaskRequest -----

PatchTaskRequest::PatchTaskRequest(RequestSender* sender,
                                   const std::string& task_list_id,
                                   const std::string& task_id,
                                   const TaskRequestPayload& payload,
                                   Callback callback)
    : UrlFetchRequestBase(sender, ProgressCallback(), ProgressCallback()),
      task_list_id_(task_list_id),
      task_id_(task_id),
      payload_(payload),
      callback_(std::move(callback)) {
  CHECK(!callback_.is_null());
  CHECK(!task_list_id_.empty());
  CHECK(!task_id_.empty());
}

PatchTaskRequest::~PatchTaskRequest() = default;

GURL PatchTaskRequest::GetURL() const {
  return GetPatchTaskUrl(task_list_id_, task_id_);
}

ApiErrorCode PatchTaskRequest::MapReasonToError(ApiErrorCode code,
                                                const std::string& reason) {
  return code;
}

bool PatchTaskRequest::IsSuccessfulErrorCode(ApiErrorCode error) {
  return error == HTTP_SUCCESS;
}

HttpRequestMethod PatchTaskRequest::GetRequestType() const {
  return HttpRequestMethod::kPatch;
}

bool PatchTaskRequest::GetContentData(std::string* upload_content_type,
                                      std::string* upload_content) {
  *upload_content_type = kContentTypeJson;
  *upload_content = payload_.ToJson();
  return true;
}

void PatchTaskRequest::ProcessURLFetchResults(
    const network::mojom::URLResponseHead* response_head,
    base::FilePath response_file,
    std::string response_body) {
  ApiErrorCode error = GetErrorCode();
  switch (error) {
    case HTTP_SUCCESS:
      blocking_task_runner()->PostTaskAndReplyWithResult(
          FROM_HERE,
          base::BindOnce(&PatchTaskRequest::Parse, std::move(response_body)),
          base::BindOnce(&PatchTaskRequest::OnDataParsed,
                         weak_ptr_factory_.GetWeakPtr()));
      break;
    default:
      RunCallbackOnPrematureFailure(error);
      OnProcessURLFetchResultsComplete();
      break;
  }
}

void PatchTaskRequest::RunCallbackOnPrematureFailure(ApiErrorCode error) {
  std::move(callback_).Run(base::unexpected(error));
}

// static
std::unique_ptr<Task> PatchTaskRequest::Parse(std::string json) {
  std::unique_ptr<base::Value> value = ParseJson(json);
  return value ? Task::CreateFrom(*value) : nullptr;
}

void PatchTaskRequest::OnDataParsed(std::unique_ptr<Task> task) {
  if (!task) {
    std::move(callback_).Run(base::unexpected(PARSE_ERROR));
  } else {
    std::move(callback_).Run(std::move(task));
  }
  OnProcessURLFetchResultsComplete();
}

// ----- InsertTaskRequest -----

InsertTaskRequest::InsertTaskRequest(RequestSender* sender,
                                     const std::string& task_list_id,
                                     const std::string& previous_task_id,
                                     const TaskRequestPayload& payload,
                                     Callback callback)
    : UrlFetchRequestBase(sender, ProgressCallback(), ProgressCallback()),
      task_list_id_(task_list_id),
      previous_task_id_(previous_task_id),
      payload_(payload),
      callback_(std::move(callback)) {
  CHECK(!task_list_id_.empty());
  CHECK(callback_);
}

InsertTaskRequest::~InsertTaskRequest() = default;

GURL InsertTaskRequest::GetURL() const {
  return GetInsertTaskUrl(task_list_id_, previous_task_id_);
}

ApiErrorCode InsertTaskRequest::MapReasonToError(ApiErrorCode code,
                                                 const std::string& reason) {
  return code;
}

bool InsertTaskRequest::IsSuccessfulErrorCode(ApiErrorCode error) {
  return error == HTTP_SUCCESS || error == HTTP_CREATED;
}

HttpRequestMethod InsertTaskRequest::GetRequestType() const {
  return HttpRequestMethod::kPost;
}

bool InsertTaskRequest::GetContentData(std::string* upload_content_type,
                                       std::string* upload_content) {
  *upload_content_type = kContentTypeJson;
  *upload_content = payload_.ToJson();
  return true;
}

void InsertTaskRequest::ProcessURLFetchResults(
    const network::mojom::URLResponseHead* response_head,
    base::FilePath response_file,
    std::string response_body) {
  ApiErrorCode error = GetErrorCode();
  switch (error) {
    case HTTP_SUCCESS:
    case HTTP_CREATED:
      blocking_task_runner()->PostTaskAndReplyWithResult(
          FROM_HERE,
          base::BindOnce(&InsertTaskRequest::Parse, std::move(response_body)),
          base::BindOnce(&InsertTaskRequest::OnDataParsed,
                         weak_ptr_factory_.GetWeakPtr()));
      break;
    default:
      RunCallbackOnPrematureFailure(error);
      OnProcessURLFetchResultsComplete();
      break;
  }
}

void InsertTaskRequest::RunCallbackOnPrematureFailure(ApiErrorCode error) {
  std::move(callback_).Run(base::unexpected(error));
}

// static
std::unique_ptr<Task> InsertTaskRequest::Parse(std::string json) {
  std::unique_ptr<base::Value> value = ParseJson(json);
  return value ? Task::CreateFrom(*value) : nullptr;
}

void InsertTaskRequest::OnDataParsed(std::unique_ptr<Task> task) {
  if (!task) {
    std::move(callback_).Run(base::unexpected(PARSE_ERROR));
  } else {
    std::move(callback_).Run(std::move(task));
  }
  OnProcessURLFetchResultsComplete();
}

}  // namespace google_apis::tasks