Add [first|middle|last]_name_native support.

This commit is contained in:
John Preston 2018-08-14 15:51:12 +03:00
parent b935d54fe7
commit 6558a32794
6 changed files with 111 additions and 73 deletions

View File

@ -151,6 +151,13 @@ void CollectToRequestedRow(
}); });
} }
void ApplyDataChanges(ValueData &data, ValueMap &&changes) {
data.parsedInEdit = data.parsed;
for (auto &[key, value] : changes.fields) {
data.parsedInEdit.fields[key] = std::move(value);
}
}
RequestedRow CollectRequestedRow(const MTPSecureRequiredType &data) { RequestedRow CollectRequestedRow(const MTPSecureRequiredType &data) {
auto result = RequestedRow(); auto result = RequestedRow();
CollectToRequestedRow(result, data); CollectToRequestedRow(result, data);
@ -220,6 +227,39 @@ QString ValidateUrl(const QString &url) {
} // namespace } // namespace
bool ValueChanged(not_null<const Value*> value, const ValueMap &data) {
const auto FileChanged = [](const EditFile &file) {
if (file.uploadData) {
return !file.deleted;
}
return file.deleted;
};
auto filesCount = 0;
for (const auto &scan : value->scansInEdit) {
if (FileChanged(scan)) {
return true;
}
}
for (const auto &[type, scan] : value->specialScansInEdit) {
if (FileChanged(scan)) {
return true;
}
}
const auto &existing = value->data.parsed.fields;
for (const auto &[key, value] : data.fields) {
const auto i = existing.find(key);
if (i != existing.end()) {
if (i->second.text != value.text) {
return true;
}
} else if (!value.text.isEmpty()) {
return true;
}
}
return false;
}
FormRequest::FormRequest( FormRequest::FormRequest(
UserId botId, UserId botId,
const QString &scope, const QString &scope,
@ -1576,42 +1616,6 @@ bool FormController::isEncryptedValue(Value::Type type) const {
return (type != Value::Type::Phone && type != Value::Type::Email); return (type != Value::Type::Phone && type != Value::Type::Email);
} }
bool FormController::editFileChanged(const EditFile &file) const {
if (file.uploadData) {
return !file.deleted;
}
return file.deleted;
}
bool FormController::editValueChanged(
not_null<const Value*> value,
const ValueMap &data) const {
auto filesCount = 0;
for (const auto &scan : value->scansInEdit) {
if (editFileChanged(scan)) {
return true;
}
}
for (const auto &[type, scan] : value->specialScansInEdit) {
if (editFileChanged(scan)) {
return true;
}
}
auto existing = value->data.parsed.fields;
for (const auto &[key, value] : data.fields) {
const auto i = existing.find(key);
if (i != existing.end()) {
if (i->second.text != value.text) {
return true;
}
existing.erase(i);
} else if (!value.text.isEmpty()) {
return true;
}
}
return !existing.empty();
}
void FormController::saveValueEdit( void FormController::saveValueEdit(
not_null<const Value*> value, not_null<const Value*> value,
ValueMap &&data) { ValueMap &&data) {
@ -1623,7 +1627,7 @@ void FormController::saveValueEdit(
// and we don't reset value->error/[scan|translation]MissingError. // and we don't reset value->error/[scan|translation]MissingError.
// Otherwise we reset them after save by re-parsing the value. // Otherwise we reset them after save by re-parsing the value.
const auto nonconst = findValue(value); const auto nonconst = findValue(value);
if (!editValueChanged(nonconst, data)) { if (!ValueChanged(nonconst, data)) {
nonconst->saveRequestId = -1; nonconst->saveRequestId = -1;
crl::on_main(this, [=] { crl::on_main(this, [=] {
base::take(nonconst->scansInEdit); base::take(nonconst->scansInEdit);
@ -1636,7 +1640,7 @@ void FormController::saveValueEdit(
}); });
return; return;
} }
nonconst->data.parsedInEdit = std::move(data); ApplyDataChanges(nonconst->data, std::move(data));
if (isEncryptedValue(nonconst->type)) { if (isEncryptedValue(nonconst->type)) {
saveEncryptedValue(nonconst); saveEncryptedValue(nonconst);

View File

@ -201,6 +201,8 @@ private:
}; };
bool ValueChanged(not_null<const Value*> value, const ValueMap &data);
struct RequestedValue { struct RequestedValue {
explicit RequestedValue(Value::Type type); explicit RequestedValue(Value::Type type);
@ -327,9 +329,6 @@ public:
void startValueEdit(not_null<const Value*> value); void startValueEdit(not_null<const Value*> value);
void cancelValueEdit(not_null<const Value*> value); void cancelValueEdit(not_null<const Value*> value);
void cancelValueVerification(not_null<const Value*> value); void cancelValueVerification(not_null<const Value*> value);
bool editValueChanged(
not_null<const Value*> value,
const ValueMap &data) const;
void saveValueEdit(not_null<const Value*> value, ValueMap &&data); void saveValueEdit(not_null<const Value*> value, ValueMap &&data);
void deleteValueEdit(not_null<const Value*> value); void deleteValueEdit(not_null<const Value*> value);
bool savingValue(not_null<const Value*> value) const; bool savingValue(not_null<const Value*> value) const;
@ -454,7 +453,6 @@ private:
void valueEditFailed(not_null<Value*> value); void valueEditFailed(not_null<Value*> value);
void clearValueEdit(not_null<Value*> value); void clearValueEdit(not_null<Value*> value);
void clearValueVerification(not_null<Value*> value); void clearValueVerification(not_null<Value*> value);
bool editFileChanged(const EditFile &file) const;
bool isEncryptedValue(Value::Type type) const; bool isEncryptedValue(Value::Type type) const;
void saveEncryptedValue(not_null<Value*> value); void saveEncryptedValue(not_null<Value*> value);

View File

@ -278,7 +278,10 @@ QString ComputeScopeRowReadyString(const Scope &scope) {
} }
return nullptr; return nullptr;
}(); }();
if (document && scope.documents.size() > 1) { if ((document && scope.documents.size() > 1)
|| (!scope.details
&& (ScopeTypeForValueType(document->type)
== Scope::Type::Address))) {
pushListValue("_type", [&] { pushListValue("_type", [&] {
using Type = Value::Type; using Type = Value::Type;
switch (document->type) { switch (document->type) {
@ -307,7 +310,10 @@ QString ComputeScopeRowReadyString(const Scope &scope) {
if (!scope.documents.empty() && !document) { if (!scope.documents.empty() && !document) {
return QString(); return QString();
} }
const auto scheme = GetDocumentScheme(scope.type); const auto scheme = GetDocumentScheme(
scope.type,
document ? base::make_optional(document->type) : base::none,
scope.details ? scope.details->nativeNames : false);
for (const auto &row : scheme.rows) { for (const auto &row : scheme.rows) {
const auto format = row.format; const auto format = row.format;
if (row.valueClass == EditDocumentScheme::ValueClass::Fields) { if (row.valueClass == EditDocumentScheme::ValueClass::Fields) {
@ -357,9 +363,10 @@ QString ComputeScopeRowReadyString(const Scope &scope) {
} }
ScopeRow ComputeScopeRow(const Scope &scope) { ScopeRow ComputeScopeRow(const Scope &scope) {
const auto addReadyError = [&](ScopeRow &&row) { const auto addReadyError = [&](
const auto ready = ComputeScopeRowReadyString(scope); ScopeRow &&row,
row.ready = ready; QString titleFallback = QString()) {
row.ready = ComputeScopeRowReadyString(scope);
auto errors = QStringList(); auto errors = QStringList();
const auto addValueErrors = [&](not_null<const Value*> value) { const auto addValueErrors = [&](not_null<const Value*> value) {
if (!value->error.isEmpty()) { if (!value->error.isEmpty()) {
@ -408,7 +415,10 @@ ScopeRow ComputeScopeRow(const Scope &scope) {
} }
if (!errors.isEmpty()) { if (!errors.isEmpty()) {
row.error = errors[0];// errors.join('\n'); row.error = errors[0];// errors.join('\n');
} else if (row.title == row.ready && !titleFallback.isEmpty()) {
row.title = titleFallback;
} }
// #TODO passport half-full value // #TODO passport half-full value
//if (row.error.isEmpty() //if (row.error.isEmpty()
// && row.ready.isEmpty() // && row.ready.isEmpty()
@ -473,27 +483,27 @@ ScopeRow ComputeScopeRow(const Scope &scope) {
return addReadyError({ return addReadyError({
lang(lng_passport_address_statement), lang(lng_passport_address_statement),
lang(lng_passport_address_statement_upload), lang(lng_passport_address_statement_upload),
}); }, lang(lng_passport_address_title));
case Value::Type::UtilityBill: case Value::Type::UtilityBill:
return addReadyError({ return addReadyError({
lang(lng_passport_address_bill), lang(lng_passport_address_bill),
lang(lng_passport_address_bill_upload), lang(lng_passport_address_bill_upload),
}); }, lang(lng_passport_address_title));
case Value::Type::RentalAgreement: case Value::Type::RentalAgreement:
return addReadyError({ return addReadyError({
lang(lng_passport_address_agreement), lang(lng_passport_address_agreement),
lang(lng_passport_address_agreement_upload), lang(lng_passport_address_agreement_upload),
}); }, lang(lng_passport_address_title));
case Value::Type::PassportRegistration: case Value::Type::PassportRegistration:
return addReadyError({ return addReadyError({
lang(lng_passport_address_registration), lang(lng_passport_address_registration),
lang(lng_passport_address_registration_upload), lang(lng_passport_address_registration_upload),
}); }, lang(lng_passport_address_title));
case Value::Type::TemporaryRegistration: case Value::Type::TemporaryRegistration:
return addReadyError({ return addReadyError({
lang(lng_passport_address_temporary), lang(lng_passport_address_temporary),
lang(lng_passport_address_temporary_upload), lang(lng_passport_address_temporary_upload),
}); }, lang(lng_passport_address_title));
default: Unexpected("Address type in ComputeScopeRow."); default: Unexpected("Address type in ComputeScopeRow.");
} }
} }

View File

@ -34,7 +34,8 @@ constexpr auto kMaxPostcodeSize = 10;
EditDocumentScheme GetDocumentScheme( EditDocumentScheme GetDocumentScheme(
Scope::Type type, Scope::Type type,
base::optional<Value::Type> scansType) { base::optional<Value::Type> scansType,
bool nativeNames) {
using Scheme = EditDocumentScheme; using Scheme = EditDocumentScheme;
using ValueClass = Scheme::ValueClass; using ValueClass = Scheme::ValueClass;
const auto DontFormat = nullptr; const auto DontFormat = nullptr;
@ -74,7 +75,8 @@ EditDocumentScheme GetDocumentScheme(
} }
return base::none; return base::none;
}; };
const auto NativeNameValidate = LimitedValidate(kMaxNameSize);
const auto NativeNameOrEmptyValidate = LimitedValidate(kMaxNameSize, 0);
const auto DocumentValidate = LimitedValidate(kMaxDocumentSize); const auto DocumentValidate = LimitedValidate(kMaxDocumentSize);
const auto StreetValidate = LimitedValidate(kMaxStreetSize); const auto StreetValidate = LimitedValidate(kMaxStreetSize);
const auto CityValidate = LimitedValidate(kMaxCitySize, kMinCitySize); const auto CityValidate = LimitedValidate(kMaxCitySize, kMinCitySize);
@ -129,35 +131,40 @@ EditDocumentScheme GetDocumentScheme(
Unexpected("scansType in GetDocumentScheme:Identity."); Unexpected("scansType in GetDocumentScheme:Identity.");
} }
} }
using Validator = EditDocumentScheme::Row::Validator;
result.rows = { result.rows = {
{ {
ValueClass::Fields, ValueClass::Fields,
PanelDetailsType::Text, PanelDetailsType::Text,
qsl("first_name"), nativeNames ? qsl("first_name_native") : qsl("first_name"),
lang(lng_passport_first_name), lang(lng_passport_first_name),
NameValidate, nativeNames ? Validator(NativeNameValidate) : NameValidate,
DontFormat, DontFormat,
kMaxNameSize, kMaxNameSize,
}, },
{ {
ValueClass::Fields, ValueClass::Fields,
PanelDetailsType::Text, PanelDetailsType::Text,
qsl("middle_name"), (nativeNames
? qsl("middle_name_native")
: qsl("middle_name")),
lang(lng_passport_middle_name), lang(lng_passport_middle_name),
NameOrEmptyValidate, (nativeNames
? Validator(NativeNameOrEmptyValidate)
: NameOrEmptyValidate),
DontFormat, DontFormat,
kMaxNameSize, kMaxNameSize,
qsl("first_name") nativeNames ? qsl("first_name_native") : qsl("first_name"),
}, },
{ {
ValueClass::Fields, ValueClass::Fields,
PanelDetailsType::Text, PanelDetailsType::Text,
qsl("last_name"), nativeNames ? qsl("last_name_native") : qsl("last_name"),
lang(lng_passport_last_name), lang(lng_passport_last_name),
NameValidate, nativeNames ? Validator(NativeNameValidate) : NameValidate,
DontFormat, DontFormat,
kMaxNameSize, kMaxNameSize,
qsl("first_name") nativeNames ? qsl("first_name_native") : qsl("first_name"),
}, },
{ {
ValueClass::Fields, ValueClass::Fields,
@ -360,6 +367,15 @@ const std::map<QString, QString> &NativeToLatinMap() {
return result; return result;
} }
QString AdjustKeyName(not_null<const Value*> value, const QString &key) {
if (!value->nativeNames) {
return key;
}
const auto &map = LatinToNativeMap();
const auto i = map.find(key);
return (i == end(map)) ? key : i->second;
}
bool SkipFieldCheck(not_null<const Value*> value, const QString &key) { bool SkipFieldCheck(not_null<const Value*> value, const QString &key) {
if (value->type != Value::Type::PersonalDetails) { if (value->type != Value::Type::PersonalDetails) {
return false; return false;
@ -1058,7 +1074,8 @@ void PanelController::startScopeEdit(int index, int documentIndex) {
this, this,
GetDocumentScheme( GetDocumentScheme(
_editScope->type, _editScope->type,
_editDocument->type), _editDocument->type,
_editValue->nativeNames),
_editValue->error, _editValue->error,
_editValue->data.parsedInEdit, _editValue->data.parsedInEdit,
_editDocument->error, _editDocument->error,
@ -1071,7 +1088,8 @@ void PanelController::startScopeEdit(int index, int documentIndex) {
this, this,
GetDocumentScheme( GetDocumentScheme(
_editScope->type, _editScope->type,
_editDocument->type), _editDocument->type,
false),
_editDocument->error, _editDocument->error,
_editDocument->data.parsedInEdit, _editDocument->data.parsedInEdit,
_editDocument->scanMissingError, _editDocument->scanMissingError,
@ -1089,7 +1107,10 @@ void PanelController::startScopeEdit(int index, int documentIndex) {
auto result = object_ptr<PanelEditDocument>( auto result = object_ptr<PanelEditDocument>(
_panel->widget(), _panel->widget(),
this, this,
GetDocumentScheme(_editScope->type), GetDocumentScheme(
_editScope->type,
base::none,
_editValue->nativeNames),
_editValue->error, _editValue->error,
_editValue->data.parsedInEdit); _editValue->data.parsedInEdit);
const auto weak = make_weak(result.data()); const auto weak = make_weak(result.data());
@ -1288,6 +1309,8 @@ void PanelController::saveScope(ValueMap &&data, ValueMap &&filesData) {
if (_editValue) { if (_editValue) {
_form->saveValueEdit(_editValue, std::move(data)); _form->saveValueEdit(_editValue, std::move(data));
} else {
Assert(data.fields.empty());
} }
if (_editDocument) { if (_editDocument) {
_form->saveValueEdit(_editDocument, std::move(filesData)); _form->saveValueEdit(_editDocument, std::move(filesData));
@ -1299,10 +1322,9 @@ void PanelController::saveScope(ValueMap &&data, ValueMap &&filesData) {
bool PanelController::editScopeChanged( bool PanelController::editScopeChanged(
const ValueMap &data, const ValueMap &data,
const ValueMap &filesData) const { const ValueMap &filesData) const {
if (_editValue && _form->editValueChanged(_editValue, data)) { if (_editValue && ValueChanged(_editValue, data)) {
return true; return true;
} else if (_editDocument } else if (_editDocument && ValueChanged(_editDocument, filesData)) {
&& _form->editValueChanged(_editDocument, filesData)) {
return true; return true;
} }
return false; return false;

View File

@ -22,11 +22,13 @@ enum class ReadScanError;
EditDocumentScheme GetDocumentScheme( EditDocumentScheme GetDocumentScheme(
Scope::Type type, Scope::Type type,
base::optional<Value::Type> scansType = base::none); base::optional<Value::Type> scansType,
bool nativeNames);
EditContactScheme GetContactScheme(Scope::Type type); EditContactScheme GetContactScheme(Scope::Type type);
const std::map<QString, QString> &LatinToNativeMap(); const std::map<QString, QString> &LatinToNativeMap();
const std::map<QString, QString> &NativeToLatinMap(); const std::map<QString, QString> &NativeToLatinMap();
QString AdjustKeyName(not_null<const Value*> value, const QString &key);
bool SkipFieldCheck(not_null<const Value*> value, const QString &key); bool SkipFieldCheck(not_null<const Value*> value, const QString &key);
struct ScanInfo { struct ScanInfo {

View File

@ -42,14 +42,16 @@ struct EditDocumentScheme {
Scans, Scans,
}; };
struct Row { struct Row {
using Validator = Fn<base::optional<QString>(const QString &value)>;
using Formatter = Fn<QString(const QString &value)>;
ValueClass valueClass = ValueClass::Fields; ValueClass valueClass = ValueClass::Fields;
PanelDetailsType inputType = PanelDetailsType(); PanelDetailsType inputType = PanelDetailsType();
QString key; QString key;
QString label; QString label;
Fn<base::optional<QString>(const QString &value)> error; Validator error;
Fn<QString(const QString &value)> format; Formatter format;
int lengthLimit = 0; int lengthLimit = 0;
QString keyForAttachmentTo; // attach last_name to first_name QString keyForAttachmentTo; // attach [last|middle]_name to first_*
}; };
std::vector<Row> rows; std::vector<Row> rows;
QString fieldsHeader; QString fieldsHeader;