Removed static storing of passport config.

This commit is contained in:
23rd 2021-10-14 00:36:48 +03:00
parent adb0a9b6f0
commit 2efd735243
7 changed files with 198 additions and 150 deletions

View file

@ -42,8 +42,6 @@ constexpr auto kTranslationScansLimit = 20;
constexpr auto kShortPollTimeout = crl::time(3000);
constexpr auto kRememberCredentialsDelay = crl::time(1800 * 1000);
Config GlobalConfig;
bool ForwardServiceErrorRequired(const QString &error) {
return (error == qstr("BOT_INVALID"))
|| (error == qstr("PUBLIC_KEY_REQUIRED"))
@ -239,46 +237,35 @@ QString ValidateUrl(const QString &url) {
: result;
}
auto ParseConfig(const QByteArray &json) {
auto languagesByCountryCode = std::map<QString, QString>();
auto error = QJsonParseError{ 0, QJsonParseError::NoError };
const auto document = QJsonDocument::fromJson(json, &error);
if (error.error != QJsonParseError::NoError) {
LOG(("API Error: Failed to parse passport config, error: %1."
).arg(error.errorString()));
return languagesByCountryCode;
} else if (!document.isObject()) {
LOG(("API Error: Not an object received in passport config."));
return languagesByCountryCode;
}
const auto object = document.object();
for (auto i = object.constBegin(); i != object.constEnd(); ++i) {
const auto countryCode = i.key();
const auto language = i.value();
if (!language.isString()) {
LOG(("API Error: Not a string in passport config item."));
continue;
}
languagesByCountryCode.emplace(
countryCode,
language.toString());
}
return languagesByCountryCode;
}
} // namespace
Config &ConfigInstance() {
return GlobalConfig;
}
Config ParseConfig(const MTPhelp_PassportConfig &data) {
return data.match([](const MTPDhelp_passportConfig &data) {
auto result = Config();
result.hash = data.vhash().v;
auto error = QJsonParseError{ 0, QJsonParseError::NoError };
const auto document = QJsonDocument::fromJson(
data.vcountries_langs().c_dataJSON().vdata().v,
&error);
if (error.error != QJsonParseError::NoError) {
LOG(("API Error: Failed to parse passport config, error: %1."
).arg(error.errorString()));
return result;
} else if (!document.isObject()) {
LOG(("API Error: Not an object received in passport config."));
return result;
}
const auto object = document.object();
for (auto i = object.constBegin(); i != object.constEnd(); ++i) {
const auto countryCode = i.key();
const auto language = i.value();
if (!language.isString()) {
LOG(("API Error: Not a string in passport config item."));
continue;
}
result.languagesByCountryCode.emplace(
countryCode,
language.toString());
}
return result;
}, [](const MTPDhelp_passportConfigNotModified &data) {
return ConfigInstance();
});
}
QString NonceNameByScope(const QString &scope) {
if (scope.startsWith('{') && scope.endsWith('}')) {
return qsl("nonce");
@ -638,7 +625,6 @@ Main::Session &FormController::session() const {
void FormController::show() {
requestForm();
requestPassword();
requestConfig();
}
UserData *FormController::bot() const {
@ -1242,6 +1228,44 @@ void FormController::fillErrors() {
}
}
rpl::producer<EditDocumentCountry> FormController::preferredLanguage(
const QString &countryCode) {
const auto findLang = [=] {
if (countryCode.isEmpty()) {
return QString();
}
auto &langs = _passportConfig.languagesByCountryCode;
const auto i = langs.find(countryCode);
return (i == end(langs)) ? QString() : i->second;
};
return [=](auto consumer) {
const auto hash = _passportConfig.hash;
if (hash) {
consumer.put_next({ countryCode, findLang() });
consumer.put_done();
return rpl::lifetime() ;
}
_api.request(MTPhelp_GetPassportConfig(
MTP_int(hash)
)).done([=](const MTPhelp_PassportConfig &result) {
result.match([&](const MTPDhelp_passportConfig &data) {
_passportConfig.hash = data.vhash().v;
_passportConfig.languagesByCountryCode = ParseConfig(
data.vcountries_langs().c_dataJSON().vdata().v);
}, [](const MTPDhelp_passportConfigNotModified &data) {
});
consumer.put_next({ countryCode, findLang() });
consumer.put_done();
}).fail([=](const MTP::Error &error) {
consumer.put_next({ countryCode, QString() });
consumer.put_done();
}).send();
return rpl::lifetime();
};
}
void FormController::fillNativeFromFallback() {
// Check if additional values (*_name_native) were requested.
const auto i = _form.values.find(Value::Type::PersonalDetails);
@ -1254,48 +1278,58 @@ void FormController::fillNativeFromFallback() {
const auto scheme = GetDocumentScheme(
Scope::Type::PersonalDetails,
std::nullopt,
true);
true,
[=](const QString &code) { return preferredLanguage(code); });
const auto dependencyIt = values.fields.find(
scheme.additionalDependencyKey);
const auto dependency = (dependencyIt == end(values.fields))
? QString()
: dependencyIt->second.text;
if (scheme.additionalShown(dependency)
!= EditDocumentScheme::AdditionalVisibility::OnlyIfError) {
return;
}
// Copy additional values from fallback if they're not filled yet.
auto changed = false;
using Scheme = EditDocumentScheme;
for (const auto &row : scheme.rows) {
if (row.valueClass == Scheme::ValueClass::Additional) {
const auto nativeIt = values.fields.find(row.key);
const auto native = (nativeIt == end(values.fields))
? QString()
: nativeIt->second.text;
if (!native.isEmpty()
|| (nativeIt != end(values.fields)
&& !nativeIt->second.error.isEmpty())) {
return;
}
const auto latinIt = values.fields.find(
row.additionalFallbackKey);
const auto latin = (latinIt == end(values.fields))
? QString()
: latinIt->second.text;
if (row.error(latin).has_value()) {
return;
} else if (native != latin) {
values.fields[row.key].text = latin;
changed = true;
scheme.preferredLanguage(
dependency
) | rpl::map(
scheme.additionalShown
) | rpl::take(
1
) | rpl::start_with_next([=](Scheme::AdditionalVisibility v) {
if (v != Scheme::AdditionalVisibility::OnlyIfError) {
return;
}
auto values = i->second.data.parsed;
auto changed = false;
for (const auto &row : scheme.rows) {
if (row.valueClass == Scheme::ValueClass::Additional) {
const auto nativeIt = values.fields.find(row.key);
const auto native = (nativeIt == end(values.fields))
? QString()
: nativeIt->second.text;
if (!native.isEmpty()
|| (nativeIt != end(values.fields)
&& !nativeIt->second.error.isEmpty())) {
return;
}
const auto latinIt = values.fields.find(
row.additionalFallbackKey);
const auto latin = (latinIt == end(values.fields))
? QString()
: latinIt->second.text;
if (row.error(latin).has_value()) {
return;
} else if (native != latin) {
values.fields[row.key].text = latin;
changed = true;
}
}
}
}
if (changed) {
startValueEdit(&i->second);
saveValueEdit(&i->second, std::move(values));
}
if (changed) {
startValueEdit(&i->second);
saveValueEdit(&i->second, std::move(values));
}
}, _lifetime);
}
void FormController::decryptValue(Value &value) const {
@ -2507,20 +2541,6 @@ void FormController::formDone(const MTPaccount_AuthorizationForm &result) {
}
}
void FormController::requestConfig() {
const auto hash = ConfigInstance().hash;
_configRequestId = _api.request(MTPhelp_GetPassportConfig(
MTP_int(hash)
)).done([=](const MTPhelp_PassportConfig &result) {
_configRequestId = 0;
ConfigInstance() = ParseConfig(result);
showForm();
}).fail([=](const MTP::Error &error) {
_configRequestId = 0;
showForm();
}).send();
}
bool FormController::parseForm(const MTPaccount_AuthorizationForm &result) {
Expects(result.type() == mtpc_account_authorizationForm);
@ -2614,7 +2634,7 @@ void FormController::shortPollEmailConfirmation() {
}
void FormController::showForm() {
if (_formRequestId || _passwordRequestId || _configRequestId) {
if (_formRequestId || _passwordRequestId) {
return;
} else if (!_bot) {
formFail(Lang::Hard::NoAuthorizationBot());

View file

@ -29,12 +29,7 @@ class Session;
namespace Passport {
struct Config {
int32 hash = 0;
std::map<QString, QString> languagesByCountryCode;
};
Config &ConfigInstance();
Config ParseConfig(const MTPhelp_PassportConfig &data);
struct EditDocumentCountry;
struct SavedCredentials {
bytes::vector hashForAuth;
@ -416,6 +411,9 @@ public:
void cancel();
void cancelSure();
[[nodiscard]] rpl::producer<EditDocumentCountry> preferredLanguage(
const QString &countryCode);
rpl::lifetime &lifetime();
~FormController();
@ -439,7 +437,6 @@ private:
void requestForm();
void requestPassword();
void requestConfig();
void formDone(const MTPaccount_AuthorizationForm &result);
void formFail(const QString &error);
@ -560,7 +557,6 @@ private:
mtpRequestId _formRequestId = 0;
mtpRequestId _passwordRequestId = 0;
mtpRequestId _passwordCheckRequestId = 0;
mtpRequestId _configRequestId = 0;
PasswordSettings _password;
crl::time _lastSrpIdInvalidTime = 0;
@ -572,6 +568,11 @@ private:
mtpRequestId _recoverRequestId = 0;
base::flat_map<FileKey, std::unique_ptr<mtpFileLoader>> _fileLoaders;
struct {
int32 hash = 0;
std::map<QString, QString> languagesByCountryCode;
} _passportConfig;
rpl::event_stream<not_null<const EditFile*>> _scanUpdated;
rpl::event_stream<not_null<const Value*>> _valueSaveFinished;
rpl::event_stream<not_null<const Value*>> _verificationNeeded;

View file

@ -377,7 +377,8 @@ QString ComputeScopeRowReadyString(const Scope &scope) {
const auto scheme = GetDocumentScheme(
scope.type,
document ? base::make_optional(document->type) : std::nullopt,
scope.details ? scope.details->nativeNames : false);
scope.details ? scope.details->nativeNames : false,
nullptr);
using ValueClass = EditDocumentScheme::ValueClass;
const auto skipAdditional = [&] {
if (!fields) {

View file

@ -117,7 +117,8 @@ std::map<FileType, ScanInfo> PrepareSpecialFiles(const Value &value) {
EditDocumentScheme GetDocumentScheme(
Scope::Type type,
std::optional<Value::Type> scansType,
bool nativeNames) {
bool nativeNames,
preferredLangCallback &&preferredLanguage) {
using Scheme = EditDocumentScheme;
using ValueClass = Scheme::ValueClass;
const auto DontFormat = nullptr;
@ -294,21 +295,17 @@ EditDocumentScheme GetDocumentScheme(
if (nativeNames) {
result.additionalDependencyKey = qsl("residence_country_code");
const auto languageValue = [](const QString &countryCode) {
if (countryCode.isEmpty()) {
return QString();
}
const auto &config = ConfigInstance();
const auto i = config.languagesByCountryCode.find(
countryCode);
if (i == end(config.languagesByCountryCode)) {
return QString();
}
return Lang::GetNonDefaultValue(
kLanguageNamePrefix + i->second.toUtf8());
result.preferredLanguage = preferredLanguage
? std::move(preferredLanguage)
: [](const QString &) {
return rpl::single(EditDocumentCountry());
};
const auto languageValue = [](const QString &langCode) {
return Lang::GetNonDefaultValue(kLanguageNamePrefix
+ langCode.toUtf8());
};
result.additionalHeader = [=](const QString &countryCode) {
const auto language = languageValue(countryCode);
result.additionalHeader = [=](const EditDocumentCountry &info) {
const auto language = languageValue(info.languageCode);
return language.isEmpty()
? tr::lng_passport_native_name_title(tr::now)
: tr::lng_passport_native_name_language(
@ -316,32 +313,28 @@ EditDocumentScheme GetDocumentScheme(
lt_language,
language);
};
result.additionalDescription = [=](const QString &countryCode) {
const auto language = languageValue(countryCode);
result.additionalDescription = [=](
const EditDocumentCountry &info) {
const auto language = languageValue(info.languageCode);
if (!language.isEmpty()) {
return tr::lng_passport_native_name_language_about(tr::now);
return tr::lng_passport_native_name_language_about(
tr::now);
}
const auto name = Countries::Instance().countryNameByISO2(
countryCode);
info.countryCode);
Assert(!name.isEmpty());
return tr::lng_passport_native_name_about(
tr::now,
lt_country,
name);
};
result.additionalShown = [](const QString &countryCode) {
result.additionalShown = [](const EditDocumentCountry &info) {
using Result = EditDocumentScheme::AdditionalVisibility;
if (countryCode.isEmpty()) {
return Result::Hidden;
}
const auto &config = ConfigInstance();
const auto i = config.languagesByCountryCode.find(
countryCode);
if (i != end(config.languagesByCountryCode)
&& i->second == "en") {
return Result::OnlyIfError;
}
return Result::Shown;
return (info.countryCode.isEmpty())
? Result::Hidden
: (info.languageCode == "en")
? Result::OnlyIfError
: Result::Shown;
};
using Row = EditDocumentScheme::Row;
auto additional = std::initializer_list<Row>{
@ -1149,6 +1142,10 @@ void PanelController::startScopeEdit(
_form->startValueEdit(_editDocument);
}
auto preferredLanguage = [=](const QString &countryCode) {
return _form->preferredLanguage(countryCode);
};
auto content = [&]() -> object_ptr<Ui::RpWidget> {
switch (_editScope->type) {
case Scope::Type::Identity:
@ -1169,7 +1166,8 @@ void PanelController::startScopeEdit(
GetDocumentScheme(
_editScope->type,
_editDocument->type,
_editValue->nativeNames),
_editValue->nativeNames,
std::move(preferredLanguage)),
_editValue->error,
_editValue->data.parsedInEdit,
_editDocument->error,
@ -1183,7 +1181,8 @@ void PanelController::startScopeEdit(
GetDocumentScheme(
_editScope->type,
_editDocument->type,
false),
false,
std::move(preferredLanguage)),
_editDocument->error,
_editDocument->data.parsedInEdit,
std::move(scans),
@ -1204,7 +1203,8 @@ void PanelController::startScopeEdit(
GetDocumentScheme(
_editScope->type,
std::nullopt,
_editValue->nativeNames),
_editValue->nativeNames,
std::move(preferredLanguage)),
_editValue->error,
_editValue->data.parsedInEdit);
const auto weak = Ui::MakeWeak(result.data());

View file

@ -20,15 +20,19 @@ namespace Passport {
class FormController;
class Panel;
struct EditDocumentCountry;
struct EditDocumentScheme;
struct EditContactScheme;
enum class ReadScanError;
using preferredLangCallback =
Fn<rpl::producer<EditDocumentCountry>(const QString &)>;
EditDocumentScheme GetDocumentScheme(
Scope::Type type,
std::optional<Value::Type> scansType,
bool nativeNames);
bool nativeNames,
preferredLangCallback &&preferredLanguage);
EditContactScheme GetContactScheme(Scope::Type type);
const std::map<QString, QString> &LatinToNativeMap();

View file

@ -425,25 +425,42 @@ not_null<Ui::RpWidget*> PanelEditDocument::setupContent(
showIfError = true;
}
});
const auto shown = [=](const QString &code) {
const auto shown = [=](const Scheme::CountryInfo &info) {
using Result = Scheme::AdditionalVisibility;
const auto value = _scheme.additionalShown(code);
const auto value = _scheme.additionalShown(info);
return (value == Result::Shown)
|| (value == Result::OnlyIfError && showIfError);
};
auto title = row->value(
) | rpl::filter(
auto langValue = row->value(
) | rpl::map(
_scheme.preferredLanguage
) | rpl::flatten_latest();
auto title = rpl::duplicate(langValue) | rpl::filter(
shown
) | rpl::map([=](const QString &code) {
return _scheme.additionalHeader(code);
) | rpl::map([=](const Scheme::CountryInfo &info) {
return _scheme.additionalHeader(info);
});
added->add(
const auto headerLabel = added->add(
object_ptr<Ui::FlatLabel>(
added,
std::move(title),
rpl::duplicate(title),
st::passportFormHeader),
st::passportNativeNameHeaderPadding);
std::move(
title
) | rpl::start_with_next([=] {
const auto &padding = st::passportNativeNameHeaderPadding;
const auto available = added->width()
- padding.left()
- padding.right();
headerLabel->resizeToNaturalWidth(available);
headerLabel->moveToLeft(
padding.left(),
padding.top(),
available);
}, headerLabel->lifetime());
enumerateRows([&](
int i,
@ -454,11 +471,10 @@ not_null<Ui::RpWidget*> PanelEditDocument::setupContent(
}
});
auto description = row->value(
) | rpl::filter(
auto description = rpl::duplicate(langValue) | rpl::filter(
shown
) | rpl::map([=](const QString &code) {
return _scheme.additionalDescription(code);
) | rpl::map([=](const Scheme::CountryInfo &info) {
return _scheme.additionalDescription(info);
});
added->add(
object_ptr<Ui::DividerLabel>(
@ -470,11 +486,10 @@ not_null<Ui::RpWidget*> PanelEditDocument::setupContent(
st::passportFormLabelPadding),
st::passportNativeNameAboutMargin);
wrap->toggleOn(row->value() | rpl::map(shown));
wrap->toggleOn(rpl::duplicate(langValue) | rpl::map(shown));
wrap->finishAnimating();
row->value(
) | rpl::map(
std::move(langValue) | rpl::map(
shown
) | rpl::start_with_next([=](bool visible) {
_additionalShown = visible;

View file

@ -39,6 +39,11 @@ class EditScans;
enum class FileType;
struct ScanListData;
struct EditDocumentCountry {
QString countryCode;
QString languageCode;
};
struct EditDocumentScheme {
enum class ValueClass {
Fields,
@ -50,6 +55,7 @@ struct EditDocumentScheme {
OnlyIfError,
Shown,
};
using CountryInfo = EditDocumentCountry;
struct Row {
using Validator = Fn<std::optional<QString>(const QString &value)>;
using Formatter = Fn<QString(const QString &value)>;
@ -69,9 +75,10 @@ struct EditDocumentScheme {
QString scansHeader;
QString additionalDependencyKey;
Fn<AdditionalVisibility(const QString &dependency)> additionalShown;
Fn<QString(const QString &dependency)> additionalHeader;
Fn<QString(const QString &dependency)> additionalDescription;
Fn<AdditionalVisibility(const CountryInfo &dependency)> additionalShown;
Fn<QString(const CountryInfo &dependency)> additionalHeader;
Fn<QString(const CountryInfo &dependency)> additionalDescription;
Fn<rpl::producer<CountryInfo>(const QString &)> preferredLanguage;
};