blob: 9520b83e0d9821d6c76222dfab548ee124fa6cd3 [file] [log] [blame]
// Copyright 2019 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/user_model.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "third_party/re2/src/re2/re2.h"
namespace autofill_assistant {
namespace {
// Matches an ASCII identifier (w+) which ends in [<string>], e.g.,
// test_identifier[sub_identifier[2]].
static const char* const kExtractArraySubidentifierRegex = R"(^(\w+)\[(.+)\]$)";
// Simple wrapper around value_util::GetNthValue to unwrap the base::optional
// |value|.
base::Optional<ValueProto> GetNthValue(const base::Optional<ValueProto>& value,
int index) {
if (!value.has_value()) {
return base::nullopt;
}
return GetNthValue(*value, index);
}
// Same as above, but expects |index_value| to point to a single integer value
// specifying the index to retrieve.
base::Optional<ValueProto> GetNthValue(
const base::Optional<ValueProto>& value,
const base::Optional<ValueProto>& index_value) {
if (!value.has_value() || !index_value.has_value()) {
return base::nullopt;
}
if (!AreAllValuesOfSize({*index_value}, 1) ||
!AreAllValuesOfType({*index_value}, ValueProto::kInts)) {
return base::nullopt;
}
return GetNthValue(*value, index_value->ints().values().at(0));
}
} // namespace
UserModel::Observer::Observer() = default;
UserModel::Observer::~Observer() = default;
UserModel::UserModel() = default;
UserModel::~UserModel() = default;
base::WeakPtr<UserModel> UserModel::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
void UserModel::SetValue(const std::string& identifier,
const ValueProto& value,
bool force_notification) {
auto result = values_.emplace(identifier, value);
if (!force_notification && !result.second && result.first->second == value) {
return;
} else if (!result.second) {
result.first->second = value;
}
for (auto& observer : observers_) {
observer.OnValueChanged(identifier, value);
}
}
base::Optional<ValueProto> UserModel::GetValue(
const std::string& identifier) const {
auto it = values_.find(identifier);
if (it != values_.end()) {
return it->second;
} else if (base::EndsWith(identifier, "]", base::CompareCase::SENSITIVE)) {
std::string identifier_without_suffix;
std::string subidentifier;
if (re2::RE2::FullMatch(identifier, kExtractArraySubidentifierRegex,
&identifier_without_suffix, &subidentifier)) {
int index;
if (base::StringToInt(subidentifier, &index)) {
// The case 'identifier[n]'.
return GetNthValue(GetValue(identifier_without_suffix), index);
} else {
// The case 'identifier[subidentifier]'.
return GetNthValue(GetValue(identifier_without_suffix),
GetValue(subidentifier));
}
}
}
return base::nullopt;
}
base::Optional<ValueProto> UserModel::GetValue(
const ValueReferenceProto& reference) const {
switch (reference.kind_case()) {
case ValueReferenceProto::kValue:
return reference.value();
case ValueReferenceProto::kModelIdentifier:
return GetValue(reference.model_identifier());
case ValueReferenceProto::KIND_NOT_SET:
return base::nullopt;
}
}
void UserModel::MergeWithProto(const ModelProto& another,
bool force_notifications) {
for (const auto& another_value : another.values()) {
if (another_value.value() == ValueProto()) {
// std::map::emplace does not overwrite existing values.
if (values_.emplace(another_value.identifier(), another_value.value())
.second ||
force_notifications) {
for (auto& observer : observers_) {
observer.OnValueChanged(another_value.identifier(),
another_value.value());
}
}
continue;
}
SetValue(another_value.identifier(), another_value.value(),
force_notifications);
}
}
void UserModel::UpdateProto(ModelProto* model_proto) const {
for (auto& model_value : *model_proto->mutable_values()) {
auto it = values_.find(model_value.identifier());
if (it != values_.end()) {
*model_value.mutable_value() = (it->second);
}
}
}
void UserModel::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void UserModel::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void UserModel::AddCreditCard(
std::unique_ptr<autofill::CreditCard> credit_card) {
if (!credit_card) {
return;
}
credit_cards_[credit_card->guid()] = std::move(credit_card);
}
void UserModel::AddProfile(std::unique_ptr<autofill::AutofillProfile> profile) {
if (!profile) {
return;
}
profiles_[profile->guid()] = std::move(profile);
}
const autofill::CreditCard* UserModel::GetCreditCard(
const std::string& guid) const {
auto it = credit_cards_.find(guid);
if (it == credit_cards_.end()) {
return nullptr;
}
return it->second.get();
}
const autofill::AutofillProfile* UserModel::GetProfile(
const std::string& guid) const {
auto it = profiles_.find(guid);
if (it == profiles_.end()) {
return nullptr;
}
return it->second.get();
}
} // namespace autofill_assistant