blob: 55586f9a8d294d710558d2e3e531908212b03324 [file] [log] [blame]
// Copyright 2020 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 "components/autofill_assistant/browser/generic_ui_replace_placeholders.h"
#include "base/logging.h"
#include "components/autofill_assistant/browser/field_formatter.h"
namespace autofill_assistant {
// Forward declaration to allow recursive calls.
void ReplacePlaceholdersInGenericUi(
GenericUserInterfaceProto* in_out_proto,
const std::map<std::string, std::string>& placeholders);
namespace {
void ReplaceInPlace(std::string* in_out,
const std::map<std::string, std::string>& placeholders) {
auto formatted_string = field_formatter::FormatString(*in_out, placeholders,
/*strict = */ false);
if (!formatted_string.has_value()) {
VLOG(1) << "lenient placeholder replacement failed";
return;
}
in_out->assign(*formatted_string);
}
void ReplacePlaceholdersInView(
ViewProto* in_out_proto,
const std::map<std::string, std::string>& placeholders) {
if (in_out_proto->has_identifier()) {
ReplaceInPlace(in_out_proto->mutable_identifier(), placeholders);
}
switch (in_out_proto->view_case()) {
case ViewProto::kViewContainer:
for (auto& child :
*in_out_proto->mutable_view_container()->mutable_views()) {
ReplacePlaceholdersInView(&child, placeholders);
}
return;
case ViewProto::kTextView:
switch (in_out_proto->text_view().kind_case()) {
case TextViewProto::kModelIdentifier:
ReplaceInPlace(
in_out_proto->mutable_text_view()->mutable_model_identifier(),
placeholders);
return;
case TextViewProto::kText:
case TextViewProto::KIND_NOT_SET:
return;
}
return;
case ViewProto::kVerticalExpanderView: {
if (in_out_proto->vertical_expander_view().has_title_view()) {
ReplacePlaceholdersInView(in_out_proto->mutable_vertical_expander_view()
->mutable_title_view(),
placeholders);
}
if (in_out_proto->vertical_expander_view().has_collapsed_view()) {
ReplacePlaceholdersInView(in_out_proto->mutable_vertical_expander_view()
->mutable_collapsed_view(),
placeholders);
}
if (in_out_proto->vertical_expander_view().has_expanded_view()) {
ReplacePlaceholdersInView(in_out_proto->mutable_vertical_expander_view()
->mutable_expanded_view(),
placeholders);
}
return;
}
case ViewProto::kTextInputView: {
if (in_out_proto->text_input_view().has_model_identifier()) {
ReplaceInPlace(
in_out_proto->mutable_text_input_view()->mutable_model_identifier(),
placeholders);
}
return;
}
case ViewProto::kToggleButtonView:
if (in_out_proto->toggle_button_view().has_model_identifier()) {
ReplaceInPlace(in_out_proto->mutable_toggle_button_view()
->mutable_model_identifier(),
placeholders);
}
if (in_out_proto->toggle_button_view().has_left_content_view()) {
ReplacePlaceholdersInView(in_out_proto->mutable_toggle_button_view()
->mutable_left_content_view(),
placeholders);
}
if (in_out_proto->toggle_button_view().has_right_content_view()) {
ReplacePlaceholdersInView(in_out_proto->mutable_toggle_button_view()
->mutable_right_content_view(),
placeholders);
}
return;
case ViewProto::kDividerView:
case ViewProto::kImageView:
case ViewProto::VIEW_NOT_SET:
return;
}
}
void ReplacePlaceholdersInEvent(
EventProto* in_out_proto,
const std::map<std::string, std::string>& placeholders) {
switch (in_out_proto->kind_case()) {
case EventProto::kOnValueChanged:
if (in_out_proto->on_value_changed().has_model_identifier()) {
ReplaceInPlace(in_out_proto->mutable_on_value_changed()
->mutable_model_identifier(),
placeholders);
}
return;
case EventProto::kOnViewClicked:
if (in_out_proto->on_view_clicked().has_view_identifier()) {
ReplaceInPlace(
in_out_proto->mutable_on_view_clicked()->mutable_view_identifier(),
placeholders);
}
return;
case EventProto::kOnViewContainerCleared:
if (in_out_proto->on_view_container_cleared().has_view_identifier()) {
ReplaceInPlace(in_out_proto->mutable_on_view_container_cleared()
->mutable_view_identifier(),
placeholders);
}
return;
case EventProto::kOnPopupDismissed:
if (in_out_proto->on_popup_dismissed().has_popup_identifier()) {
ReplaceInPlace(in_out_proto->mutable_on_popup_dismissed()
->mutable_popup_identifier(),
placeholders);
}
return;
case EventProto::kOnUserActionCalled:
case EventProto::kOnTextLinkClicked:
case EventProto::KIND_NOT_SET:
return;
}
return;
}
void ReplacePlaceholdersInValue(
ValueReferenceProto* in_out_proto,
const std::map<std::string, std::string>& placeholders) {
switch (in_out_proto->kind_case()) {
case ValueReferenceProto::kModelIdentifier:
ReplaceInPlace(in_out_proto->mutable_model_identifier(), placeholders);
return;
case ValueReferenceProto::kValue:
case ValueReferenceProto::KIND_NOT_SET:
return;
}
}
void ReplacePlaceholdersInInteraction(
InteractionProto* in_out_proto,
const std::map<std::string, std::string>& placeholders) {
for (auto& trigger_event : *in_out_proto->mutable_trigger_event()) {
ReplacePlaceholdersInEvent(&trigger_event, placeholders);
}
for (auto& callback : *in_out_proto->mutable_callbacks()) {
ReplacePlaceholdersInCallback(&callback, placeholders);
}
}
void ReplacePlaceholdersInModel(
ModelProto* in_out_proto,
const std::map<std::string, std::string>& placeholders) {
for (auto& value : *in_out_proto->mutable_values()) {
if (value.has_identifier()) {
ReplaceInPlace(value.mutable_identifier(), placeholders);
}
}
}
} // namespace
void ReplacePlaceholdersInGenericUi(
GenericUserInterfaceProto* in_out_proto,
const std::map<std::string, std::string>& placeholders) {
if (placeholders.empty()) {
return;
}
if (in_out_proto->has_root_view()) {
ReplacePlaceholdersInView(in_out_proto->mutable_root_view(), placeholders);
}
for (auto& interaction :
*in_out_proto->mutable_interactions()->mutable_interactions()) {
ReplacePlaceholdersInInteraction(&interaction, placeholders);
}
if (in_out_proto->has_model()) {
ReplacePlaceholdersInModel(in_out_proto->mutable_model(), placeholders);
}
}
void ReplacePlaceholdersInCallback(
CallbackProto* in_out_proto,
const std::map<std::string, std::string>& placeholders) {
if (in_out_proto->has_condition_model_identifier()) {
ReplaceInPlace(in_out_proto->mutable_condition_model_identifier(),
placeholders);
}
switch (in_out_proto->kind_case()) {
case CallbackProto::kSetValue:
if (in_out_proto->set_value().has_model_identifier()) {
ReplaceInPlace(
in_out_proto->mutable_set_value()->mutable_model_identifier(),
placeholders);
}
if (in_out_proto->set_value().has_value()) {
ReplacePlaceholdersInValue(
in_out_proto->mutable_set_value()->mutable_value(), placeholders);
}
return;
case CallbackProto::kShowListPopup:
if (in_out_proto->show_list_popup().has_item_names()) {
ReplacePlaceholdersInValue(
in_out_proto->mutable_show_list_popup()->mutable_item_names(),
placeholders);
}
if (in_out_proto->show_list_popup().has_item_types()) {
ReplacePlaceholdersInValue(
in_out_proto->mutable_show_list_popup()->mutable_item_types(),
placeholders);
}
if (in_out_proto->show_list_popup()
.has_selected_item_indices_model_identifier()) {
ReplaceInPlace(in_out_proto->mutable_show_list_popup()
->mutable_selected_item_indices_model_identifier(),
placeholders);
}
if (in_out_proto->show_list_popup()
.has_selected_item_names_model_identifier()) {
ReplaceInPlace(in_out_proto->mutable_show_list_popup()
->mutable_selected_item_names_model_identifier(),
placeholders);
}
return;
case CallbackProto::kComputeValue:
if (in_out_proto->compute_value().has_result_model_identifier()) {
ReplaceInPlace(in_out_proto->mutable_compute_value()
->mutable_result_model_identifier(),
placeholders);
}
switch (in_out_proto->compute_value().kind_case()) {
case ComputeValueProto::kBooleanAnd:
for (auto& value : *in_out_proto->mutable_compute_value()
->mutable_boolean_and()
->mutable_values()) {
ReplacePlaceholdersInValue(&value, placeholders);
}
return;
case ComputeValueProto::kBooleanOr:
for (auto& value : *in_out_proto->mutable_compute_value()
->mutable_boolean_or()
->mutable_values()) {
ReplacePlaceholdersInValue(&value, placeholders);
}
return;
case ComputeValueProto::kBooleanNot:
if (in_out_proto->compute_value().boolean_not().has_value()) {
ReplacePlaceholdersInValue(in_out_proto->mutable_compute_value()
->mutable_boolean_not()
->mutable_value(),
placeholders);
}
return;
case ComputeValueProto::kToString:
if (in_out_proto->compute_value().to_string().has_value()) {
ReplacePlaceholdersInValue(in_out_proto->mutable_compute_value()
->mutable_to_string()
->mutable_value(),
placeholders);
}
return;
case ComputeValueProto::kComparison:
if (in_out_proto->compute_value().comparison().has_value_a()) {
ReplacePlaceholdersInValue(in_out_proto->mutable_compute_value()
->mutable_comparison()
->mutable_value_a(),
placeholders);
}
if (in_out_proto->compute_value().comparison().has_value_b()) {
ReplacePlaceholdersInValue(in_out_proto->mutable_compute_value()
->mutable_comparison()
->mutable_value_b(),
placeholders);
}
return;
case ComputeValueProto::kIntegerSum:
for (auto& value : *in_out_proto->mutable_compute_value()
->mutable_integer_sum()
->mutable_values()) {
ReplacePlaceholdersInValue(&value, placeholders);
}
return;
case ComputeValueProto::kCreateCreditCardResponse:
if (in_out_proto->compute_value()
.create_credit_card_response()
.has_value()) {
ReplacePlaceholdersInValue(
in_out_proto->mutable_compute_value()
->mutable_create_credit_card_response()
->mutable_value(),
placeholders);
}
return;
case ComputeValueProto::kCreateLoginOptionResponse:
if (in_out_proto->compute_value()
.create_login_option_response()
.has_value()) {
ReplacePlaceholdersInValue(
in_out_proto->mutable_compute_value()
->mutable_create_login_option_response()
->mutable_value(),
placeholders);
}
return;
case ComputeValueProto::kStringEmpty:
if (in_out_proto->compute_value().string_empty().has_value()) {
ReplacePlaceholdersInValue(in_out_proto->mutable_compute_value()
->mutable_string_empty()
->mutable_value(),
placeholders);
}
return;
case ComputeValueProto::KIND_NOT_SET:
return;
}
case CallbackProto::kSetUserActions:
if (in_out_proto->set_user_actions().has_user_actions()) {
ReplacePlaceholdersInValue(
in_out_proto->mutable_set_user_actions()->mutable_user_actions(),
placeholders);
}
return;
case CallbackProto::kShowCalendarPopup:
if (in_out_proto->show_calendar_popup().has_date_model_identifier()) {
ReplaceInPlace(in_out_proto->mutable_show_calendar_popup()
->mutable_date_model_identifier(),
placeholders);
}
if (in_out_proto->show_calendar_popup().has_min_date()) {
ReplacePlaceholdersInValue(
in_out_proto->mutable_show_calendar_popup()->mutable_min_date(),
placeholders);
}
if (in_out_proto->show_calendar_popup().has_max_date()) {
ReplacePlaceholdersInValue(
in_out_proto->mutable_show_calendar_popup()->mutable_max_date(),
placeholders);
}
return;
case CallbackProto::kSetText:
if (in_out_proto->set_text().has_text()) {
ReplacePlaceholdersInValue(
in_out_proto->mutable_set_text()->mutable_text(), placeholders);
}
if (in_out_proto->set_text().has_view_identifier()) {
ReplaceInPlace(
in_out_proto->mutable_set_text()->mutable_view_identifier(),
placeholders);
}
return;
case CallbackProto::kToggleUserAction:
if (in_out_proto->toggle_user_action()
.has_user_actions_model_identifier()) {
ReplaceInPlace(in_out_proto->mutable_toggle_user_action()
->mutable_user_actions_model_identifier(),
placeholders);
}
if (in_out_proto->toggle_user_action().has_enabled()) {
ReplacePlaceholdersInValue(
in_out_proto->mutable_toggle_user_action()->mutable_enabled(),
placeholders);
}
return;
case CallbackProto::kSetViewVisibility:
if (in_out_proto->set_view_visibility().has_view_identifier()) {
ReplaceInPlace(in_out_proto->mutable_set_view_visibility()
->mutable_view_identifier(),
placeholders);
}
if (in_out_proto->set_view_visibility().has_visible()) {
ReplacePlaceholdersInValue(
in_out_proto->mutable_set_view_visibility()->mutable_visible(),
placeholders);
}
return;
case CallbackProto::kSetViewEnabled:
if (in_out_proto->set_view_enabled().has_view_identifier()) {
ReplaceInPlace(
in_out_proto->mutable_set_view_enabled()->mutable_view_identifier(),
placeholders);
}
if (in_out_proto->set_view_enabled().has_enabled()) {
ReplacePlaceholdersInValue(
in_out_proto->mutable_set_view_enabled()->mutable_enabled(),
placeholders);
}
return;
case CallbackProto::kShowGenericPopup:
if (in_out_proto->show_generic_popup().has_popup_identifier()) {
ReplaceInPlace(in_out_proto->mutable_show_generic_popup()
->mutable_popup_identifier(),
placeholders);
}
if (in_out_proto->show_generic_popup().has_generic_ui()) {
ReplacePlaceholdersInGenericUi(
in_out_proto->mutable_show_generic_popup()->mutable_generic_ui(),
placeholders);
}
return;
case CallbackProto::kCreateNestedUi:
if (in_out_proto->create_nested_ui().has_generic_ui_identifier()) {
ReplaceInPlace(in_out_proto->mutable_create_nested_ui()
->mutable_generic_ui_identifier(),
placeholders);
}
if (in_out_proto->create_nested_ui().has_generic_ui()) {
ReplacePlaceholdersInGenericUi(
in_out_proto->mutable_create_nested_ui()->mutable_generic_ui(),
placeholders);
}
if (in_out_proto->create_nested_ui().has_parent_view_identifier()) {
ReplaceInPlace(in_out_proto->mutable_create_nested_ui()
->mutable_parent_view_identifier(),
placeholders);
}
return;
case CallbackProto::kClearViewContainer:
if (in_out_proto->clear_view_container().has_view_identifier()) {
ReplaceInPlace(in_out_proto->mutable_clear_view_container()
->mutable_view_identifier(),
placeholders);
}
return;
case CallbackProto::kForEach:
if (in_out_proto->for_each().has_loop_value_model_identifier()) {
ReplaceInPlace(in_out_proto->mutable_for_each()
->mutable_loop_value_model_identifier(),
placeholders);
}
for (auto& callback :
*in_out_proto->mutable_for_each()->mutable_callbacks()) {
ReplacePlaceholdersInCallback(&callback, placeholders);
}
return;
case CallbackProto::kShowInfoPopup:
case CallbackProto::kEndAction:
case CallbackProto::KIND_NOT_SET:
return;
}
}
} // namespace autofill_assistant