mirror of https://github.com/procxx/kepka.git
Start improved passport support.
This commit is contained in:
parent
bdab477040
commit
3c43f621ce
|
@ -1668,7 +1668,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_passport_error_cant_read" = "Can't read this file. Please choose an image.";
|
"lng_passport_error_cant_read" = "Can't read this file. Please choose an image.";
|
||||||
"lng_passport_bad_name" = "Please use latin characters only.";
|
"lng_passport_bad_name" = "Please use latin characters only.";
|
||||||
"lng_passport_wait_upload" = "Please wait while upload is finished.";
|
"lng_passport_wait_upload" = "Please wait while upload is finished.";
|
||||||
"lng_passport_fix_errors" = "Please correct errors.";
|
|
||||||
"lng_passport_app_out_of_date" = "Sorry, your Telegram app is out of date and can't handle this request. Please update Telegram.";
|
"lng_passport_app_out_of_date" = "Sorry, your Telegram app is out of date and can't handle this request. Please update Telegram.";
|
||||||
|
|
||||||
"lng_export_title" = "Export Personal Data";
|
"lng_export_title" = "Export Personal Data";
|
||||||
|
|
|
@ -995,9 +995,9 @@ secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType;
|
||||||
secureValueTypePhone#b320aadb = SecureValueType;
|
secureValueTypePhone#b320aadb = SecureValueType;
|
||||||
secureValueTypeEmail#8e3ca7ee = SecureValueType;
|
secureValueTypeEmail#8e3ca7ee = SecureValueType;
|
||||||
|
|
||||||
secureValue#b4b4b699 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile files:flags.4?Vector<SecureFile> plain_data:flags.5?SecurePlainData hash:bytes = SecureValue;
|
secureValue#187fa0ca flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile translation:flags.6?Vector<SecureFile> files:flags.4?Vector<SecureFile> plain_data:flags.5?SecurePlainData hash:bytes = SecureValue;
|
||||||
|
|
||||||
inputSecureValue#67872e8 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile files:flags.4?Vector<InputSecureFile> plain_data:flags.5?SecurePlainData = InputSecureValue;
|
inputSecureValue#db21d0a7 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile translation:flags.6?Vector<InputSecureFile> files:flags.4?Vector<InputSecureFile> plain_data:flags.5?SecurePlainData = InputSecureValue;
|
||||||
|
|
||||||
secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash;
|
secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash;
|
||||||
|
|
||||||
|
@ -1007,10 +1007,13 @@ secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:s
|
||||||
secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError;
|
secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError;
|
||||||
secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError;
|
secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError;
|
||||||
secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector<bytes> text:string = SecureValueError;
|
secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector<bytes> text:string = SecureValueError;
|
||||||
|
secureValueError#869d758f type:SecureValueType hash:bytes text:string = SecureValueError;
|
||||||
|
secureValueErrorTranslationFile#a1144770 type:SecureValueType file_hash:bytes text:string = SecureValueError;
|
||||||
|
secureValueErrorTranslationFiles#34636dd8 type:SecureValueType file_hash:Vector<bytes> text:string = SecureValueError;
|
||||||
|
|
||||||
secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted;
|
secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted;
|
||||||
|
|
||||||
account.authorizationForm#cb976d53 flags:# selfie_required:flags.1?true required_types:Vector<SecureValueType> values:Vector<SecureValue> errors:Vector<SecureValueError> users:Vector<User> privacy_policy_url:flags.0?string = account.AuthorizationForm;
|
account.authorizationForm#ad2e1cd8 flags:# required_types:Vector<SecureRequiredType> values:Vector<SecureValue> errors:Vector<SecureValueError> users:Vector<User> privacy_policy_url:flags.0?string = account.AuthorizationForm;
|
||||||
|
|
||||||
account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode;
|
account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode;
|
||||||
|
|
||||||
|
@ -1033,6 +1036,9 @@ secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:by
|
||||||
inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP;
|
inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP;
|
||||||
inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP;
|
inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP;
|
||||||
|
|
||||||
|
secureRequiredType#829d99da flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType;
|
||||||
|
secureRequiredTypeOneOf#27477b4 types:Vector<SecureRequiredType> = SecureRequiredType;
|
||||||
|
|
||||||
---functions---
|
---functions---
|
||||||
|
|
||||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||||
|
@ -1321,4 +1327,4 @@ langpack.getStrings#2e1ee318 lang_code:string keys:Vector<string> = Vector<LangP
|
||||||
langpack.getDifference#b2e4d7d from_version:int = LangPackDifference;
|
langpack.getDifference#b2e4d7d from_version:int = LangPackDifference;
|
||||||
langpack.getLanguages#800fd57d = Vector<LangPackLanguage>;
|
langpack.getLanguages#800fd57d = Vector<LangPackLanguage>;
|
||||||
|
|
||||||
// LAYER 84
|
// LAYER 85
|
||||||
|
|
|
@ -132,7 +132,30 @@ MTPSecureValueType ConvertType(Value::Type type) {
|
||||||
return MTP_secureValueTypeEmail();
|
return MTP_secureValueTypeEmail();
|
||||||
}
|
}
|
||||||
Unexpected("Type in FormController::submit.");
|
Unexpected("Type in FormController::submit.");
|
||||||
};
|
}
|
||||||
|
|
||||||
|
void CollectToRequestedRow(
|
||||||
|
RequestedRow &row,
|
||||||
|
const MTPSecureRequiredType &data) {
|
||||||
|
data.match([&](const MTPDsecureRequiredType &data) {
|
||||||
|
row.values.emplace_back(ConvertType(data.vtype));
|
||||||
|
auto &value = row.values.back();
|
||||||
|
value.selfieRequired = data.is_selfie_required();
|
||||||
|
value.translationRequired = data.is_translation_required();
|
||||||
|
value.nativeNames = data.is_native_names();
|
||||||
|
}, [&](const MTPDsecureRequiredTypeOneOf &data) {
|
||||||
|
row.values.reserve(row.values.size() + data.vtypes.v.size());
|
||||||
|
for (const auto &one : data.vtypes.v) {
|
||||||
|
CollectToRequestedRow(row, one);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestedRow CollectRequestedRow(const MTPSecureRequiredType &data) {
|
||||||
|
auto result = RequestedRow();
|
||||||
|
CollectToRequestedRow(result, data);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
QJsonObject GetJSONFromMap(
|
QJsonObject GetJSONFromMap(
|
||||||
const std::map<QString, bytes::const_span> &map) {
|
const std::map<QString, bytes::const_span> &map) {
|
||||||
|
@ -257,12 +280,13 @@ UploadScanData *UploadScanDataPointer::operator->() const {
|
||||||
return _value.get();
|
return _value.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RequestedValue::RequestedValue(Value::Type type) : type(type) {
|
||||||
|
}
|
||||||
|
|
||||||
Value::Value(Type type) : type(type) {
|
Value::Value(Type type) : type(type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Value::requiresSpecialScan(
|
bool Value::requiresSpecialScan(SpecialFile type) const {
|
||||||
SpecialFile type,
|
|
||||||
bool selfieRequired) const {
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SpecialFile::FrontSide:
|
case SpecialFile::FrontSide:
|
||||||
return (this->type == Type::Passport)
|
return (this->type == Type::Passport)
|
||||||
|
@ -278,9 +302,11 @@ bool Value::requiresSpecialScan(
|
||||||
Unexpected("Special scan type in requiresSpecialScan.");
|
Unexpected("Special scan type in requiresSpecialScan.");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Value::scansAreFilled(bool selfieRequired) const {
|
bool Value::scansAreFilled() const {
|
||||||
if (!requiresSpecialScan(SpecialFile::FrontSide, selfieRequired)) {
|
if (!requiresSpecialScan(SpecialFile::FrontSide) && scans.empty()) {
|
||||||
return !scans.empty();
|
return false;
|
||||||
|
} else if (translationRequired && translations.empty()) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
const auto types = {
|
const auto types = {
|
||||||
SpecialFile::FrontSide,
|
SpecialFile::FrontSide,
|
||||||
|
@ -288,14 +314,13 @@ bool Value::scansAreFilled(bool selfieRequired) const {
|
||||||
SpecialFile::Selfie
|
SpecialFile::Selfie
|
||||||
};
|
};
|
||||||
for (const auto type : types) {
|
for (const auto type : types) {
|
||||||
if (requiresSpecialScan(type, selfieRequired)
|
if (requiresSpecialScan(type)
|
||||||
&& (specialScans.find(type) == end(specialScans))) {
|
&& (specialScans.find(type) == end(specialScans))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
FormController::FormController(
|
FormController::FormController(
|
||||||
not_null<Window::Controller*> controller,
|
not_null<Window::Controller*> controller,
|
||||||
|
@ -346,8 +371,7 @@ auto FormController::prepareFinalData() -> FinalData {
|
||||||
object.insert("files", files);
|
object.insert("files", files);
|
||||||
}
|
}
|
||||||
for (const auto &[type, scan] : value->specialScans) {
|
for (const auto &[type, scan] : value->specialScans) {
|
||||||
const auto selfieRequired = _form.identitySelfieRequired;
|
if (value->requiresSpecialScan(type)) {
|
||||||
if (value->requiresSpecialScan(type, selfieRequired)) {
|
|
||||||
object.insert(
|
object.insert(
|
||||||
SpecialScanCredentialsKey(type),
|
SpecialScanCredentialsKey(type),
|
||||||
GetJSONFromFile(scan));
|
GetJSONFromFile(scan));
|
||||||
|
@ -364,17 +388,21 @@ auto FormController::prepareFinalData() -> FinalData {
|
||||||
addValueToJSON(key, value);
|
addValueToJSON(key, value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const auto scopes = ComputeScopes(this);
|
const auto scopes = ComputeScopes(_form);
|
||||||
for (const auto &scope : scopes) {
|
for (const auto &scope : scopes) {
|
||||||
const auto row = ComputeScopeRow(scope);
|
const auto row = ComputeScopeRow(scope);
|
||||||
if (row.ready.isEmpty() || !row.error.isEmpty()) {
|
if (row.ready.isEmpty() || !row.error.isEmpty()) {
|
||||||
errors.push_back(scope.fields);
|
errors.push_back(scope.details
|
||||||
|
? scope.details
|
||||||
|
: scope.documents[0].get());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
addValue(scope.fields);
|
if (scope.details) {
|
||||||
|
addValue(scope.details);
|
||||||
|
}
|
||||||
if (!scope.documents.empty()) {
|
if (!scope.documents.empty()) {
|
||||||
for (const auto &document : scope.documents) {
|
for (const auto &document : scope.documents) {
|
||||||
if (document->scansAreFilled(scope.selfieRequired)) {
|
if (document->scansAreFilled()) {
|
||||||
addValue(document);
|
addValue(document);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -803,6 +831,7 @@ void FormController::decryptValues() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormController::fillErrors() {
|
void FormController::fillErrors() {
|
||||||
|
// #TODO passport filter by flags
|
||||||
const auto find = [&](const MTPSecureValueType &type) -> Value* {
|
const auto find = [&](const MTPSecureValueType &type) -> Value* {
|
||||||
const auto converted = ConvertType(type);
|
const auto converted = ConvertType(type);
|
||||||
const auto i = _form.values.find(ConvertType(type));
|
const auto i = _form.values.find(ConvertType(type));
|
||||||
|
@ -835,43 +864,44 @@ void FormController::fillErrors() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
for (const auto &error : _form.pendingErrors) {
|
for (const auto &error : _form.pendingErrors) {
|
||||||
switch (error.type()) {
|
error.match([&](const MTPDsecureValueError &data) {
|
||||||
case mtpc_secureValueErrorData: {
|
if (const auto value = find(data.vtype)) {
|
||||||
const auto &data = error.c_secureValueErrorData();
|
value->error = qs(data.vtext);
|
||||||
|
}
|
||||||
|
}, [&](const MTPDsecureValueErrorData &data) {
|
||||||
if (const auto value = find(data.vtype)) {
|
if (const auto value = find(data.vtype)) {
|
||||||
const auto key = qs(data.vfield);
|
const auto key = qs(data.vfield);
|
||||||
value->data.parsed.fields[key].error = qs(data.vtext);
|
value->data.parsed.fields[key].error = qs(data.vtext);
|
||||||
}
|
}
|
||||||
} break;
|
}, [&](const MTPDsecureValueErrorFile &data) {
|
||||||
case mtpc_secureValueErrorFile: {
|
|
||||||
const auto &data = error.c_secureValueErrorFile();
|
|
||||||
const auto hash = bytes::make_span(data.vfile_hash.v);
|
const auto hash = bytes::make_span(data.vfile_hash.v);
|
||||||
if (const auto value = find(data.vtype)) {
|
if (const auto value = find(data.vtype)) {
|
||||||
if (const auto file = scan(*value, hash)) {
|
if (const auto file = scan(*value, hash)) {
|
||||||
file->error = qs(data.vtext);
|
file->error = qs(data.vtext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
}, [&](const MTPDsecureValueErrorFiles &data) {
|
||||||
case mtpc_secureValueErrorFiles: {
|
|
||||||
const auto &data = error.c_secureValueErrorFiles();
|
|
||||||
if (const auto value = find(data.vtype)) {
|
if (const auto value = find(data.vtype)) {
|
||||||
value->scanMissingError = qs(data.vtext);
|
value->scanMissingError = qs(data.vtext);
|
||||||
}
|
}
|
||||||
} break;
|
}, [&](const MTPDsecureValueErrorTranslationFile &data) {
|
||||||
case mtpc_secureValueErrorFrontSide: {
|
const auto hash = bytes::make_span(data.vfile_hash.v);
|
||||||
const auto &data = error.c_secureValueErrorFrontSide();
|
if (const auto value = find(data.vtype)) {
|
||||||
|
if (const auto file = scan(*value, hash)) { // #TODO passport
|
||||||
|
file->error = qs(data.vtext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [&](const MTPDsecureValueErrorTranslationFiles &data) {
|
||||||
|
if (const auto value = find(data.vtype)) {
|
||||||
|
value->translationMissingError = qs(data.vtext);
|
||||||
|
}
|
||||||
|
}, [&](const MTPDsecureValueErrorFrontSide &data) {
|
||||||
setSpecialScanError(SpecialFile::FrontSide, data);
|
setSpecialScanError(SpecialFile::FrontSide, data);
|
||||||
} break;
|
}, [&](const MTPDsecureValueErrorReverseSide &data) {
|
||||||
case mtpc_secureValueErrorReverseSide: {
|
|
||||||
const auto &data = error.c_secureValueErrorReverseSide();
|
|
||||||
setSpecialScanError(SpecialFile::ReverseSide, data);
|
setSpecialScanError(SpecialFile::ReverseSide, data);
|
||||||
} break;
|
}, [&](const MTPDsecureValueErrorSelfie &data) {
|
||||||
case mtpc_secureValueErrorSelfie: {
|
|
||||||
const auto &data = error.c_secureValueErrorSelfie();
|
|
||||||
setSpecialScanError(SpecialFile::Selfie, data);
|
setSpecialScanError(SpecialFile::Selfie, data);
|
||||||
} break;
|
});
|
||||||
default: Unexpected("Error type in FormController::fillErrors.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1312,9 +1342,13 @@ void FormController::startValueEdit(not_null<const Value*> value) {
|
||||||
for (auto &scan : nonconst->scans) {
|
for (auto &scan : nonconst->scans) {
|
||||||
loadFile(scan);
|
loadFile(scan);
|
||||||
}
|
}
|
||||||
|
if (nonconst->translationRequired) {
|
||||||
|
for (auto &scan : nonconst->translations) {
|
||||||
|
loadFile(scan);
|
||||||
|
}
|
||||||
|
}
|
||||||
for (auto &[type, scan] : nonconst->specialScans) {
|
for (auto &[type, scan] : nonconst->specialScans) {
|
||||||
const auto selfieRequired = _form.identitySelfieRequired;
|
if (nonconst->requiresSpecialScan(type)) {
|
||||||
if (nonconst->requiresSpecialScan(type, selfieRequired)) {
|
|
||||||
loadFile(scan);
|
loadFile(scan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1324,6 +1358,12 @@ void FormController::startValueEdit(not_null<const Value*> value) {
|
||||||
return EditFile(nonconst, file, nullptr);
|
return EditFile(nonconst, file, nullptr);
|
||||||
}) | ranges::to_vector;
|
}) | ranges::to_vector;
|
||||||
|
|
||||||
|
nonconst->translationsInEdit = ranges::view::all(
|
||||||
|
nonconst->translations
|
||||||
|
) | ranges::view::transform([=](const File &file) {
|
||||||
|
return EditFile(nonconst, file, nullptr);
|
||||||
|
}) | ranges::to_vector;
|
||||||
|
|
||||||
nonconst->specialScansInEdit.clear();
|
nonconst->specialScansInEdit.clear();
|
||||||
for (const auto &[type, scan] : nonconst->specialScans) {
|
for (const auto &[type, scan] : nonconst->specialScans) {
|
||||||
nonconst->specialScansInEdit.emplace(type, EditFile(
|
nonconst->specialScansInEdit.emplace(type, EditFile(
|
||||||
|
@ -1597,7 +1637,7 @@ void FormController::saveEncryptedValue(not_null<Value*> value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto inputFile = [](const EditFile &file) {
|
const auto wrapFile = [](const EditFile &file) {
|
||||||
if (const auto uploadData = file.uploadData.get()) {
|
if (const auto uploadData = file.uploadData.get()) {
|
||||||
return MTP_inputSecureFileUploaded(
|
return MTP_inputSecureFileUploaded(
|
||||||
MTP_long(file.fields.id),
|
MTP_long(file.fields.id),
|
||||||
|
@ -1611,13 +1651,22 @@ void FormController::saveEncryptedValue(not_null<Value*> value) {
|
||||||
MTP_long(file.fields.accessHash));
|
MTP_long(file.fields.accessHash));
|
||||||
};
|
};
|
||||||
|
|
||||||
auto inputFiles = QVector<MTPInputSecureFile>();
|
auto files = QVector<MTPInputSecureFile>();
|
||||||
inputFiles.reserve(value->scansInEdit.size());
|
files.reserve(value->scansInEdit.size());
|
||||||
for (const auto &scan : value->scansInEdit) {
|
for (const auto &scan : value->scansInEdit) {
|
||||||
if (scan.deleted) {
|
if (scan.deleted) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
inputFiles.push_back(inputFile(scan));
|
files.push_back(wrapFile(scan));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto translations = QVector<MTPInputSecureFile>();
|
||||||
|
translations.reserve(value->translationsInEdit.size());
|
||||||
|
for (const auto &scan : value->translationsInEdit) {
|
||||||
|
if (scan.deleted) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
translations.push_back(wrapFile(scan));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value->data.secret.empty()) {
|
if (value->data.secret.empty()) {
|
||||||
|
@ -1639,7 +1688,7 @@ void FormController::saveEncryptedValue(not_null<Value*> value) {
|
||||||
const auto specialFile = [&](SpecialFile type) {
|
const auto specialFile = [&](SpecialFile type) {
|
||||||
const auto i = value->specialScansInEdit.find(type);
|
const auto i = value->specialScansInEdit.find(type);
|
||||||
return (i != end(value->specialScansInEdit) && !i->second.deleted)
|
return (i != end(value->specialScansInEdit) && !i->second.deleted)
|
||||||
? inputFile(i->second)
|
? wrapFile(i->second)
|
||||||
: MTPInputSecureFile();
|
: MTPInputSecureFile();
|
||||||
};
|
};
|
||||||
const auto frontSide = specialFile(SpecialFile::FrontSide);
|
const auto frontSide = specialFile(SpecialFile::FrontSide);
|
||||||
|
@ -1659,6 +1708,9 @@ void FormController::saveEncryptedValue(not_null<Value*> value) {
|
||||||
| (hasSpecialFile(SpecialFile::Selfie)
|
| (hasSpecialFile(SpecialFile::Selfie)
|
||||||
? MTPDinputSecureValue::Flag::f_selfie
|
? MTPDinputSecureValue::Flag::f_selfie
|
||||||
: MTPDinputSecureValue::Flag(0))
|
: MTPDinputSecureValue::Flag(0))
|
||||||
|
| (value->translationsInEdit.empty()
|
||||||
|
? MTPDinputSecureValue::Flag(0)
|
||||||
|
: MTPDinputSecureValue::Flag::f_translation)
|
||||||
| (value->scansInEdit.empty()
|
| (value->scansInEdit.empty()
|
||||||
? MTPDinputSecureValue::Flag(0)
|
? MTPDinputSecureValue::Flag(0)
|
||||||
: MTPDinputSecureValue::Flag::f_files);
|
: MTPDinputSecureValue::Flag::f_files);
|
||||||
|
@ -1674,7 +1726,8 @@ void FormController::saveEncryptedValue(not_null<Value*> value) {
|
||||||
frontSide,
|
frontSide,
|
||||||
reverseSide,
|
reverseSide,
|
||||||
selfie,
|
selfie,
|
||||||
MTP_vector<MTPInputSecureFile>(inputFiles),
|
MTP_vector<MTPInputSecureFile>(translations),
|
||||||
|
MTP_vector<MTPInputSecureFile>(files),
|
||||||
MTPSecurePlainData()));
|
MTPSecurePlainData()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1704,6 +1757,7 @@ void FormController::savePlainTextValue(not_null<Value*> value) {
|
||||||
MTPInputSecureFile(),
|
MTPInputSecureFile(),
|
||||||
MTPInputSecureFile(),
|
MTPInputSecureFile(),
|
||||||
MTPVector<MTPInputSecureFile>(),
|
MTPVector<MTPInputSecureFile>(),
|
||||||
|
MTPVector<MTPInputSecureFile>(),
|
||||||
plain(MTP_string(text))));
|
plain(MTP_string(text))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2157,13 +2211,14 @@ auto FormController::findFile(const FileKey &key)
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormController::formDone(const MTPaccount_AuthorizationForm &result) {
|
void FormController::formDone(const MTPaccount_AuthorizationForm &result) {
|
||||||
parseForm(result);
|
if (!parseForm(result)) {
|
||||||
if (!_passwordRequestId) {
|
_view->showCriticalError(lang(lng_passport_form_error));
|
||||||
|
} else if (!_passwordRequestId) {
|
||||||
showForm();
|
showForm();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormController::parseForm(const MTPaccount_AuthorizationForm &result) {
|
bool FormController::parseForm(const MTPaccount_AuthorizationForm &result) {
|
||||||
Expects(result.type() == mtpc_account_authorizationForm);
|
Expects(result.type() == mtpc_account_authorizationForm);
|
||||||
|
|
||||||
const auto &data = result.c_account_authorizationForm();
|
const auto &data = result.c_account_authorizationForm();
|
||||||
|
@ -2177,21 +2232,34 @@ void FormController::parseForm(const MTPaccount_AuthorizationForm &result) {
|
||||||
if (alreadyIt != _form.values.end()) {
|
if (alreadyIt != _form.values.end()) {
|
||||||
LOG(("API Error: Two values for type %1 in authorization form"
|
LOG(("API Error: Two values for type %1 in authorization form"
|
||||||
"%1").arg(int(type)));
|
"%1").arg(int(type)));
|
||||||
continue;
|
return false;
|
||||||
}
|
}
|
||||||
_form.values.emplace(type, std::move(parsed));
|
_form.values.emplace(type, std::move(parsed));
|
||||||
}
|
}
|
||||||
_form.identitySelfieRequired = data.is_selfie_required();
|
|
||||||
if (data.has_privacy_policy_url()) {
|
if (data.has_privacy_policy_url()) {
|
||||||
_form.privacyPolicyUrl = qs(data.vprivacy_policy_url);
|
_form.privacyPolicyUrl = qs(data.vprivacy_policy_url);
|
||||||
}
|
}
|
||||||
for (const auto &required : data.vrequired_types.v) {
|
for (const auto &required : data.vrequired_types.v) {
|
||||||
const auto type = ConvertType(required);
|
const auto row = CollectRequestedRow(required);
|
||||||
_form.request.push_back(type);
|
for (const auto value : row.values) {
|
||||||
_form.values.emplace(type, Value(type));
|
const auto [i, ok] = _form.values.emplace(
|
||||||
|
value.type,
|
||||||
|
Value(value.type));
|
||||||
|
i->second.selfieRequired = value.selfieRequired;
|
||||||
|
i->second.translationRequired = value.translationRequired;
|
||||||
|
i->second.nativeNames = value.nativeNames;
|
||||||
|
}
|
||||||
|
_form.request.push_back(row.values
|
||||||
|
| ranges::view::transform([](const RequestedValue &value) {
|
||||||
|
return value.type;
|
||||||
|
}) | ranges::to_vector);
|
||||||
|
}
|
||||||
|
if (!ValidateForm(_form)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
_bot = App::userLoaded(_request.botId);
|
_bot = App::userLoaded(_request.botId);
|
||||||
_form.pendingErrors = data.verrors.v;
|
_form.pendingErrors = data.verrors.v;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormController::formFail(const QString &error) {
|
void FormController::formFail(const QString &error) {
|
||||||
|
|
|
@ -168,31 +168,52 @@ struct Value {
|
||||||
Value(Value &&other) = default;
|
Value(Value &&other) = default;
|
||||||
Value &operator=(Value &&other) = default;
|
Value &operator=(Value &&other) = default;
|
||||||
|
|
||||||
bool requiresSpecialScan(SpecialFile type, bool selfieRequired) const;
|
bool requiresSpecialScan(SpecialFile type) const;
|
||||||
bool scansAreFilled(bool selfieRequired) const;
|
bool scansAreFilled() const;
|
||||||
|
|
||||||
Type type;
|
Type type;
|
||||||
ValueData data;
|
ValueData data;
|
||||||
std::vector<File> scans;
|
std::vector<File> scans;
|
||||||
|
std::vector<File> translations;
|
||||||
std::map<SpecialFile, File> specialScans;
|
std::map<SpecialFile, File> specialScans;
|
||||||
|
QString error;
|
||||||
QString scanMissingError;
|
QString scanMissingError;
|
||||||
|
QString translationMissingError;
|
||||||
std::vector<EditFile> scansInEdit;
|
std::vector<EditFile> scansInEdit;
|
||||||
|
std::vector<EditFile> translationsInEdit;
|
||||||
std::map<SpecialFile, EditFile> specialScansInEdit;
|
std::map<SpecialFile, EditFile> specialScansInEdit;
|
||||||
Verification verification;
|
Verification verification;
|
||||||
bytes::vector submitHash;
|
bytes::vector submitHash;
|
||||||
|
|
||||||
|
bool selfieRequired = false;
|
||||||
|
bool translationRequired = false;
|
||||||
|
bool nativeNames = false;
|
||||||
|
|
||||||
int editScreens = 0;
|
int editScreens = 0;
|
||||||
mtpRequestId saveRequestId = 0;
|
mtpRequestId saveRequestId = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RequestedValue {
|
||||||
|
explicit RequestedValue(Value::Type type);
|
||||||
|
|
||||||
|
Value::Type type;
|
||||||
|
bool selfieRequired = false;
|
||||||
|
bool translationRequired = false;
|
||||||
|
bool nativeNames = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RequestedRow {
|
||||||
|
std::vector<RequestedValue> values;
|
||||||
|
};
|
||||||
|
|
||||||
struct Form {
|
struct Form {
|
||||||
|
using Request = std::vector<std::vector<Value::Type>>;
|
||||||
|
|
||||||
std::map<Value::Type, Value> values;
|
std::map<Value::Type, Value> values;
|
||||||
std::vector<Value::Type> request;
|
Request request;
|
||||||
bool identitySelfieRequired = false;
|
|
||||||
QString privacyPolicyUrl;
|
QString privacyPolicyUrl;
|
||||||
QVector<MTPSecureValueError> pendingErrors;
|
QVector<MTPSecureValueError> pendingErrors;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PasswordSettings {
|
struct PasswordSettings {
|
||||||
|
@ -333,7 +354,7 @@ private:
|
||||||
|
|
||||||
void formDone(const MTPaccount_AuthorizationForm &result);
|
void formDone(const MTPaccount_AuthorizationForm &result);
|
||||||
void formFail(const QString &error);
|
void formFail(const QString &error);
|
||||||
void parseForm(const MTPaccount_AuthorizationForm &result);
|
bool parseForm(const MTPaccount_AuthorizationForm &result);
|
||||||
void showForm();
|
void showForm();
|
||||||
Value parseValue(
|
Value parseValue(
|
||||||
const MTPSecureValue &value,
|
const MTPSecureValue &value,
|
||||||
|
|
|
@ -18,12 +18,12 @@ namespace {
|
||||||
|
|
||||||
std::map<Value::Type, Scope::Type> ScopeTypesMap() {
|
std::map<Value::Type, Scope::Type> ScopeTypesMap() {
|
||||||
return {
|
return {
|
||||||
{ Value::Type::PersonalDetails, Scope::Type::Identity },
|
{ Value::Type::PersonalDetails, Scope::Type::PersonalDetails },
|
||||||
{ Value::Type::Passport, Scope::Type::Identity },
|
{ Value::Type::Passport, Scope::Type::Identity },
|
||||||
{ Value::Type::DriverLicense, Scope::Type::Identity },
|
{ Value::Type::DriverLicense, Scope::Type::Identity },
|
||||||
{ Value::Type::IdentityCard, Scope::Type::Identity },
|
{ Value::Type::IdentityCard, Scope::Type::Identity },
|
||||||
{ Value::Type::InternalPassport, Scope::Type::Identity },
|
{ Value::Type::InternalPassport, Scope::Type::Identity },
|
||||||
{ Value::Type::Address, Scope::Type::Address },
|
{ Value::Type::Address, Scope::Type::AddressDetails },
|
||||||
{ Value::Type::UtilityBill, Scope::Type::Address },
|
{ Value::Type::UtilityBill, Scope::Type::Address },
|
||||||
{ Value::Type::BankStatement, Scope::Type::Address },
|
{ Value::Type::BankStatement, Scope::Type::Address },
|
||||||
{ Value::Type::RentalAgreement, Scope::Type::Address },
|
{ Value::Type::RentalAgreement, Scope::Type::Address },
|
||||||
|
@ -41,62 +41,141 @@ Scope::Type ScopeTypeForValueType(Value::Type type) {
|
||||||
return i->second;
|
return i->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<Scope::Type, Value::Type> ScopeFieldsMap() {
|
std::map<Scope::Type, Value::Type> ScopeDetailsMap() {
|
||||||
return {
|
return {
|
||||||
|
{ Scope::Type::PersonalDetails, Value::Type::PersonalDetails },
|
||||||
{ Scope::Type::Identity, Value::Type::PersonalDetails },
|
{ Scope::Type::Identity, Value::Type::PersonalDetails },
|
||||||
|
{ Scope::Type::AddressDetails, Value::Type::Address },
|
||||||
{ Scope::Type::Address, Value::Type::Address },
|
{ Scope::Type::Address, Value::Type::Address },
|
||||||
{ Scope::Type::Phone, Value::Type::Phone },
|
{ Scope::Type::Phone, Value::Type::Phone },
|
||||||
{ Scope::Type::Email, Value::Type::Email },
|
{ Scope::Type::Email, Value::Type::Email },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Type FieldsTypeForScopeType(Scope::Type type) {
|
Value::Type DetailsTypeForScopeType(Scope::Type type) {
|
||||||
static const auto map = ScopeFieldsMap();
|
static const auto map = ScopeDetailsMap();
|
||||||
const auto i = map.find(type);
|
const auto i = map.find(type);
|
||||||
Assert(i != map.end());
|
Assert(i != map.end());
|
||||||
return i->second;
|
return i->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
bool InlineDetails(
|
||||||
|
const Form::Request &request,
|
||||||
|
Scope::Type into,
|
||||||
|
Value::Type details) {
|
||||||
|
const auto count = ranges::count_if(
|
||||||
|
request,
|
||||||
|
[&](const std::vector<Value::Type> &types) {
|
||||||
|
Expects(!types.empty());
|
||||||
|
|
||||||
Scope::Scope(Type type, not_null<const Value*> fields)
|
return ScopeTypeForValueType(types[0]) == into;
|
||||||
: type(type)
|
});
|
||||||
, fields(fields) {
|
if (count != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto has = ranges::find_if(
|
||||||
|
request,
|
||||||
|
[&](const std::vector<Value::Type> &types) {
|
||||||
|
Expects(!types.empty());
|
||||||
|
|
||||||
|
return (types[0] == details);
|
||||||
|
}
|
||||||
|
) != end(request);
|
||||||
|
return has;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Scope> ComputeScopes(
|
bool InlineDetails(const Form::Request &request, Value::Type details) {
|
||||||
not_null<const FormController*> controller) {
|
if (details == Value::Type::PersonalDetails) {
|
||||||
auto scopes = std::map<Scope::Type, Scope>();
|
return InlineDetails(request, Scope::Type::Identity, details);
|
||||||
const auto &form = controller->form();
|
} else if (details == Value::Type::Address) {
|
||||||
|
return InlineDetails(request, Scope::Type::Address, details);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Scope::Scope(Type type) : type(type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ValidateForm(const Form &form) {
|
||||||
|
base::flat_set<Value::Type> values;
|
||||||
|
for (const auto &requested : form.request) {
|
||||||
|
if (requested.empty()) {
|
||||||
|
LOG(("API Error: Empty types list in authorization form row."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto scopeType = ScopeTypeForValueType(requested[0]);
|
||||||
|
const auto ownsDetails = (scopeType != Scope::Type::Identity
|
||||||
|
&& scopeType != Scope::Type::Address);
|
||||||
|
if (ownsDetails && requested.size() != 1) {
|
||||||
|
LOG(("API Error: Large types list in authorization form row."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (const auto type : requested) {
|
||||||
|
if (values.contains(type)) {
|
||||||
|
LOG(("API Error: Value twice in authorization form row."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
values.emplace(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto &[type, value] : form.values) {
|
||||||
|
if (!value.translationRequired) {
|
||||||
|
for (const auto &scan : value.translations) {
|
||||||
|
if (!scan.error.isEmpty()) {
|
||||||
|
LOG(("API Error: "
|
||||||
|
"Translation error in authorization form value."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!value.translationMissingError.isEmpty()) {
|
||||||
|
LOG(("API Error: "
|
||||||
|
"Translations error in authorization form value."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto &[type, specialScan] : value.specialScans) {
|
||||||
|
if (!value.requiresSpecialScan(type)
|
||||||
|
&& !specialScan.error.isEmpty()) {
|
||||||
|
LOG(("API Error: "
|
||||||
|
"Special scan error in authorization form value."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Scope> ComputeScopes(const Form &form) {
|
||||||
|
auto result = std::vector<Scope>();
|
||||||
const auto findValue = [&](const Value::Type type) {
|
const auto findValue = [&](const Value::Type type) {
|
||||||
const auto i = form.values.find(type);
|
const auto i = form.values.find(type);
|
||||||
Assert(i != form.values.end());
|
Assert(i != form.values.end());
|
||||||
return &i->second;
|
return &i->second;
|
||||||
};
|
};
|
||||||
for (const auto type : form.request) {
|
for (const auto &requested : form.request) {
|
||||||
const auto scopeType = ScopeTypeForValueType(type);
|
Assert(!requested.empty());
|
||||||
const auto fieldsType = FieldsTypeForScopeType(scopeType);
|
const auto scopeType = ScopeTypeForValueType(requested[0]);
|
||||||
const auto [i, ok] = scopes.emplace(
|
const auto detailsType = DetailsTypeForScopeType(scopeType);
|
||||||
scopeType,
|
const auto ownsDetails = (scopeType != Scope::Type::Identity
|
||||||
Scope(scopeType, findValue(fieldsType)));
|
&& scopeType != Scope::Type::Address);
|
||||||
i->second.selfieRequired = (scopeType == Scope::Type::Identity)
|
const auto inlineDetails = InlineDetails(form.request, detailsType);
|
||||||
&& form.identitySelfieRequired;
|
if (ownsDetails && inlineDetails) {
|
||||||
const auto alreadyIt = ranges::find(
|
|
||||||
i->second.documents,
|
|
||||||
type,
|
|
||||||
[](not_null<const Value*> value) { return value->type; });
|
|
||||||
if (alreadyIt != end(i->second.documents)) {
|
|
||||||
LOG(("API Error: Value type %1 multiple times in request."
|
|
||||||
).arg(int(type)));
|
|
||||||
continue;
|
continue;
|
||||||
} else if (type != fieldsType) {
|
|
||||||
i->second.documents.push_back(findValue(type));
|
|
||||||
}
|
}
|
||||||
}
|
result.push_back(Scope(scopeType));
|
||||||
auto result = std::vector<Scope>();
|
auto &scope = result.back();
|
||||||
result.reserve(scopes.size());
|
scope.details = (ownsDetails || inlineDetails)
|
||||||
for (auto &[type, scope] : scopes) {
|
? findValue(detailsType)
|
||||||
result.push_back(std::move(scope));
|
: nullptr;
|
||||||
|
if (ownsDetails) {
|
||||||
|
Assert(requested.size() == 1);
|
||||||
|
} else {
|
||||||
|
for (const auto type : requested) {
|
||||||
|
scope.documents.push_back(findValue(type));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -129,7 +208,9 @@ QString JoinScopeRowReadyString(
|
||||||
|
|
||||||
QString ComputeScopeRowReadyString(const Scope &scope) {
|
QString ComputeScopeRowReadyString(const Scope &scope) {
|
||||||
switch (scope.type) {
|
switch (scope.type) {
|
||||||
|
case Scope::Type::PersonalDetails:
|
||||||
case Scope::Type::Identity:
|
case Scope::Type::Identity:
|
||||||
|
case Scope::Type::AddressDetails:
|
||||||
case Scope::Type::Address: {
|
case Scope::Type::Address: {
|
||||||
auto list = std::vector<std::pair<QString, QString>>();
|
auto list = std::vector<std::pair<QString, QString>>();
|
||||||
const auto pushListValue = [&](
|
const auto pushListValue = [&](
|
||||||
|
@ -153,10 +234,12 @@ QString ComputeScopeRowReadyString(const Scope &scope) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const auto &fields = scope.fields->data.parsed.fields;
|
const auto fields = scope.details
|
||||||
|
? &scope.details->data.parsed.fields
|
||||||
|
: nullptr;
|
||||||
const auto document = [&]() -> const Value* {
|
const auto document = [&]() -> const Value* {
|
||||||
for (const auto &document : scope.documents) {
|
for (const auto &document : scope.documents) {
|
||||||
if (document->scansAreFilled(scope.selfieRequired)) {
|
if (document->scansAreFilled()) {
|
||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,8 +278,11 @@ QString ComputeScopeRowReadyString(const Scope &scope) {
|
||||||
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) {
|
||||||
const auto i = fields.find(row.key);
|
if (!fields) {
|
||||||
if (i == end(fields)) {
|
continue;
|
||||||
|
}
|
||||||
|
const auto i = fields->find(row.key);
|
||||||
|
if (i == end(*fields)) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
const auto text = i->second.text;
|
const auto text = i->second.text;
|
||||||
|
@ -225,8 +311,9 @@ QString ComputeScopeRowReadyString(const Scope &scope) {
|
||||||
} break;
|
} break;
|
||||||
case Scope::Type::Phone:
|
case Scope::Type::Phone:
|
||||||
case Scope::Type::Email: {
|
case Scope::Type::Email: {
|
||||||
|
Assert(scope.details != nullptr);
|
||||||
const auto format = GetContactScheme(scope.type).format;
|
const auto format = GetContactScheme(scope.type).format;
|
||||||
const auto &fields = scope.fields->data.parsed.fields;
|
const auto &fields = scope.details->data.parsed.fields;
|
||||||
const auto i = fields.find("value");
|
const auto i = fields.find("value");
|
||||||
return (i != end(fields))
|
return (i != end(fields))
|
||||||
? (format ? format(i->second.text) : i->second.text)
|
? (format ? format(i->second.text) : i->second.text)
|
||||||
|
@ -242,19 +329,30 @@ ScopeRow ComputeScopeRow(const Scope &scope) {
|
||||||
row.ready = ready;
|
row.ready = ready;
|
||||||
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()) {
|
||||||
|
errors.push_back(value->error);
|
||||||
|
}
|
||||||
|
if (!value->scanMissingError.isEmpty()) {
|
||||||
|
errors.push_back(value->scanMissingError);
|
||||||
|
}
|
||||||
|
if (!value->translationMissingError.isEmpty()) {
|
||||||
|
errors.push_back(value->translationMissingError);
|
||||||
|
}
|
||||||
for (const auto &scan : value->scans) {
|
for (const auto &scan : value->scans) {
|
||||||
if (!scan.error.isEmpty()) {
|
if (!scan.error.isEmpty()) {
|
||||||
errors.push_back(scan.error);
|
errors.push_back(scan.error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (const auto &scan : value->translations) {
|
||||||
|
if (!scan.error.isEmpty()) {
|
||||||
|
errors.push_back(scan.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
for (const auto &[type, scan] : value->specialScans) {
|
for (const auto &[type, scan] : value->specialScans) {
|
||||||
if (!scan.error.isEmpty()) {
|
if (!scan.error.isEmpty()) {
|
||||||
errors.push_back(scan.error);
|
errors.push_back(scan.error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!value->scanMissingError.isEmpty()) {
|
|
||||||
errors.push_back(value->scanMissingError);
|
|
||||||
}
|
|
||||||
for (const auto &[key, value] : value->data.parsed.fields) {
|
for (const auto &[key, value] : value->data.parsed.fields) {
|
||||||
if (!value.error.isEmpty()) {
|
if (!value.error.isEmpty()) {
|
||||||
errors.push_back(value.error);
|
errors.push_back(value.error);
|
||||||
|
@ -263,7 +361,7 @@ ScopeRow ComputeScopeRow(const Scope &scope) {
|
||||||
};
|
};
|
||||||
const auto document = [&]() -> const Value* {
|
const auto document = [&]() -> const Value* {
|
||||||
for (const auto &document : scope.documents) {
|
for (const auto &document : scope.documents) {
|
||||||
if (document->scansAreFilled(scope.selfieRequired)) {
|
if (document->scansAreFilled()) {
|
||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -272,31 +370,35 @@ ScopeRow ComputeScopeRow(const Scope &scope) {
|
||||||
if (document) {
|
if (document) {
|
||||||
addValueErrors(document);
|
addValueErrors(document);
|
||||||
}
|
}
|
||||||
addValueErrors(scope.fields);
|
if (scope.details) {
|
||||||
|
addValueErrors(scope.details);
|
||||||
|
}
|
||||||
if (!errors.isEmpty()) {
|
if (!errors.isEmpty()) {
|
||||||
row.error = lang(lng_passport_fix_errors);// errors.join('\n');
|
row.error = errors[0];// errors.join('\n');
|
||||||
}
|
|
||||||
if (row.error.isEmpty()
|
|
||||||
&& row.ready.isEmpty()
|
|
||||||
&& scope.type == Scope::Type::Identity
|
|
||||||
&& scope.selfieRequired) {
|
|
||||||
auto noSelfieScope = scope;
|
|
||||||
noSelfieScope.selfieRequired = false;
|
|
||||||
if (!ComputeScopeRowReadyString(noSelfieScope).isEmpty()) {
|
|
||||||
// Only selfie is missing.
|
|
||||||
row.description = lang(lng_passport_identity_selfie);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// #TODO passport half-full value
|
||||||
|
//if (row.error.isEmpty()
|
||||||
|
// && row.ready.isEmpty()
|
||||||
|
// && scope.type == Scope::Type::Identity
|
||||||
|
// && scope.selfieRequired) {
|
||||||
|
// auto noSelfieScope = scope;
|
||||||
|
// noSelfieScope.selfieRequired = false;
|
||||||
|
// if (!ComputeScopeRowReadyString(noSelfieScope).isEmpty()) {
|
||||||
|
// // Only selfie is missing.
|
||||||
|
// row.description = lang(lng_passport_identity_selfie);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
return row;
|
return row;
|
||||||
};
|
};
|
||||||
switch (scope.type) {
|
switch (scope.type) {
|
||||||
|
case Scope::Type::PersonalDetails:
|
||||||
|
return addReadyError({
|
||||||
|
lang(lng_passport_personal_details),
|
||||||
|
lang(lng_passport_personal_details_enter),
|
||||||
|
});
|
||||||
case Scope::Type::Identity:
|
case Scope::Type::Identity:
|
||||||
if (scope.documents.empty()) {
|
Assert(!scope.documents.empty());
|
||||||
return addReadyError({
|
if (scope.documents.size() == 1) {
|
||||||
lang(lng_passport_personal_details),
|
|
||||||
lang(lng_passport_personal_details_enter),
|
|
||||||
});
|
|
||||||
} else if (scope.documents.size() == 1) {
|
|
||||||
switch (scope.documents.front()->type) {
|
switch (scope.documents.front()->type) {
|
||||||
case Value::Type::Passport:
|
case Value::Type::Passport:
|
||||||
return addReadyError({
|
return addReadyError({
|
||||||
|
@ -325,13 +427,14 @@ ScopeRow ComputeScopeRow(const Scope &scope) {
|
||||||
lang(lng_passport_identity_title),
|
lang(lng_passport_identity_title),
|
||||||
lang(lng_passport_identity_description),
|
lang(lng_passport_identity_description),
|
||||||
});
|
});
|
||||||
case Scope::Type::Address:
|
case Scope::Type::AddressDetails:
|
||||||
if (scope.documents.empty()) {
|
return addReadyError({
|
||||||
return addReadyError({
|
lang(lng_passport_address),
|
||||||
lang(lng_passport_address),
|
lang(lng_passport_address_enter),
|
||||||
lang(lng_passport_address_enter),
|
|
||||||
});
|
});
|
||||||
} else if (scope.documents.size() == 1) {
|
case Scope::Type::Address:
|
||||||
|
Assert(!scope.documents.empty());
|
||||||
|
if (scope.documents.size() == 1) {
|
||||||
switch (scope.documents.front()->type) {
|
switch (scope.documents.front()->type) {
|
||||||
case Value::Type::BankStatement:
|
case Value::Type::BankStatement:
|
||||||
return addReadyError({
|
return addReadyError({
|
||||||
|
|
|
@ -13,17 +13,18 @@ namespace Passport {
|
||||||
|
|
||||||
struct Scope {
|
struct Scope {
|
||||||
enum class Type {
|
enum class Type {
|
||||||
|
PersonalDetails,
|
||||||
Identity,
|
Identity,
|
||||||
|
AddressDetails,
|
||||||
Address,
|
Address,
|
||||||
Phone,
|
Phone,
|
||||||
Email,
|
Email,
|
||||||
};
|
};
|
||||||
Scope(Type type, not_null<const Value*> fields);
|
explicit Scope(Type type);
|
||||||
|
|
||||||
Type type;
|
Type type;
|
||||||
not_null<const Value*> fields;
|
const Value *details = nullptr;
|
||||||
std::vector<not_null<const Value*>> documents;
|
std::vector<not_null<const Value*>> documents;
|
||||||
bool selfieRequired = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ScopeRow {
|
struct ScopeRow {
|
||||||
|
@ -33,8 +34,8 @@ struct ScopeRow {
|
||||||
QString error;
|
QString error;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Scope> ComputeScopes(
|
bool ValidateForm(const Form &form);
|
||||||
not_null<const FormController*> controller);
|
std::vector<Scope> ComputeScopes(const Form &form);
|
||||||
QString ComputeScopeRowReadyString(const Scope &scope);
|
QString ComputeScopeRowReadyString(const Scope &scope);
|
||||||
ScopeRow ComputeScopeRow(const Scope &scope);
|
ScopeRow ComputeScopeRow(const Scope &scope);
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,7 @@ EditDocumentScheme GetDocumentScheme(
|
||||||
return !CountryFormat(value).isEmpty();
|
return !CountryFormat(value).isEmpty();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// #TODO passport scheme
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Scope::Type::Identity: {
|
case Scope::Type::Identity: {
|
||||||
auto result = Scheme();
|
auto result = Scheme();
|
||||||
|
@ -360,7 +361,7 @@ BoxContent *BoxPointer::operator->() const {
|
||||||
|
|
||||||
PanelController::PanelController(not_null<FormController*> form)
|
PanelController::PanelController(not_null<FormController*> form)
|
||||||
: _form(form)
|
: _form(form)
|
||||||
, _scopes(ComputeScopes(_form)) {
|
, _scopes(ComputeScopes(_form->form())) {
|
||||||
_form->secretReadyEvents(
|
_form->secretReadyEvents(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
ensurePanelCreated();
|
ensurePanelCreated();
|
||||||
|
@ -378,8 +379,6 @@ PanelController::PanelController(not_null<FormController*> form)
|
||||||
}) | rpl::start_with_next([=](not_null<const Value*> field) {
|
}) | rpl::start_with_next([=](not_null<const Value*> field) {
|
||||||
_verificationBoxes.erase(field);
|
_verificationBoxes.erase(field);
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
_scopes = ComputeScopes(_form);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<UserData*> PanelController::bot() const {
|
not_null<UserData*> PanelController::bot() const {
|
||||||
|
@ -397,12 +396,14 @@ void PanelController::fillRows(
|
||||||
bool ready,
|
bool ready,
|
||||||
bool error)> callback) {
|
bool error)> callback) {
|
||||||
if (_scopes.empty()) {
|
if (_scopes.empty()) {
|
||||||
_scopes = ComputeScopes(_form);
|
_scopes = ComputeScopes(_form->form());
|
||||||
}
|
}
|
||||||
for (const auto &scope : _scopes) {
|
for (const auto &scope : _scopes) {
|
||||||
const auto row = ComputeScopeRow(scope);
|
const auto row = ComputeScopeRow(scope);
|
||||||
const auto main = scope.fields;
|
const auto main = scope.details
|
||||||
if (!row.ready.isEmpty()) {
|
? not_null<const Value*>(scope.details)
|
||||||
|
: scope.documents[0];
|
||||||
|
if (main && !row.ready.isEmpty()) {
|
||||||
_submitErrors.erase(
|
_submitErrors.erase(
|
||||||
ranges::remove(_submitErrors, main),
|
ranges::remove(_submitErrors, main),
|
||||||
_submitErrors.end());
|
_submitErrors.end());
|
||||||
|
@ -546,9 +547,7 @@ void PanelController::uploadSpecialScan(
|
||||||
QByteArray &&content) {
|
QByteArray &&content) {
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editScope != nullptr);
|
||||||
Expects(_editDocument != nullptr);
|
Expects(_editDocument != nullptr);
|
||||||
Expects(_editDocument->requiresSpecialScan(
|
Expects(_editDocument->requiresSpecialScan(type));
|
||||||
type,
|
|
||||||
_editScope->selfieRequired));
|
|
||||||
|
|
||||||
_form->uploadSpecialScan(_editDocument, type, std::move(content));
|
_form->uploadSpecialScan(_editDocument, type, std::move(content));
|
||||||
}
|
}
|
||||||
|
@ -556,9 +555,7 @@ void PanelController::uploadSpecialScan(
|
||||||
void PanelController::deleteSpecialScan(SpecialFile type) {
|
void PanelController::deleteSpecialScan(SpecialFile type) {
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editScope != nullptr);
|
||||||
Expects(_editDocument != nullptr);
|
Expects(_editDocument != nullptr);
|
||||||
Expects(_editDocument->requiresSpecialScan(
|
Expects(_editDocument->requiresSpecialScan(type));
|
||||||
type,
|
|
||||||
_editScope->selfieRequired));
|
|
||||||
|
|
||||||
_form->deleteSpecialScan(_editDocument, type);
|
_form->deleteSpecialScan(_editDocument, type);
|
||||||
}
|
}
|
||||||
|
@ -566,9 +563,7 @@ void PanelController::deleteSpecialScan(SpecialFile type) {
|
||||||
void PanelController::restoreSpecialScan(SpecialFile type) {
|
void PanelController::restoreSpecialScan(SpecialFile type) {
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editScope != nullptr);
|
||||||
Expects(_editDocument != nullptr);
|
Expects(_editDocument != nullptr);
|
||||||
Expects(_editDocument->requiresSpecialScan(
|
Expects(_editDocument->requiresSpecialScan(type));
|
||||||
type,
|
|
||||||
_editScope->selfieRequired));
|
|
||||||
|
|
||||||
_form->restoreSpecialScan(_editDocument, type);
|
_form->restoreSpecialScan(_editDocument, type);
|
||||||
}
|
}
|
||||||
|
@ -642,9 +637,15 @@ ScanInfo PanelController::collectScanInfo(const EditFile &file) const {
|
||||||
std::vector<ScopeError> PanelController::collectErrors(
|
std::vector<ScopeError> PanelController::collectErrors(
|
||||||
not_null<const Value*> value) const {
|
not_null<const Value*> value) const {
|
||||||
auto result = std::vector<ScopeError>();
|
auto result = std::vector<ScopeError>();
|
||||||
|
if (!value->error.isEmpty()) {
|
||||||
|
result.push_back({ FileKey(), value->error });
|
||||||
|
}
|
||||||
if (!value->scanMissingError.isEmpty()) {
|
if (!value->scanMissingError.isEmpty()) {
|
||||||
result.push_back({ FileKey(), value->scanMissingError });
|
result.push_back({ FileKey(), value->scanMissingError });
|
||||||
}
|
}
|
||||||
|
if (!value->translationMissingError.isEmpty()) {
|
||||||
|
result.push_back({ FileKey(), value->translationMissingError });
|
||||||
|
}
|
||||||
const auto addFileError = [&](const EditFile &file) {
|
const auto addFileError = [&](const EditFile &file) {
|
||||||
if (!file.fields.error.isEmpty()) {
|
if (!file.fields.error.isEmpty()) {
|
||||||
const auto key = FileKey{ file.fields.id, file.fields.dcId };
|
const auto key = FileKey{ file.fields.id, file.fields.dcId };
|
||||||
|
@ -654,6 +655,9 @@ std::vector<ScopeError> PanelController::collectErrors(
|
||||||
for (const auto &scan : value->scansInEdit) {
|
for (const auto &scan : value->scansInEdit) {
|
||||||
addFileError(scan);
|
addFileError(scan);
|
||||||
}
|
}
|
||||||
|
for (const auto &scan : value->translationsInEdit) {
|
||||||
|
addFileError(scan);
|
||||||
|
}
|
||||||
for (const auto &[type, scan] : value->specialScansInEdit) {
|
for (const auto &[type, scan] : value->specialScansInEdit) {
|
||||||
addFileError(scan);
|
addFileError(scan);
|
||||||
}
|
}
|
||||||
|
@ -671,13 +675,14 @@ auto PanelController::deleteValueLabel() const
|
||||||
|
|
||||||
if (hasValueDocument()) {
|
if (hasValueDocument()) {
|
||||||
return Lang::Viewer(lng_passport_delete_document);
|
return Lang::Viewer(lng_passport_delete_document);
|
||||||
}
|
} else if (!hasValueFields()) {
|
||||||
if (!hasValueFields()) {
|
|
||||||
return base::none;
|
return base::none;
|
||||||
}
|
}
|
||||||
switch (_editScope->type) {
|
switch (_editScope->type) {
|
||||||
|
case Scope::Type::PersonalDetails:
|
||||||
case Scope::Type::Identity:
|
case Scope::Type::Identity:
|
||||||
return Lang::Viewer(lng_passport_delete_details);
|
return Lang::Viewer(lng_passport_delete_details);
|
||||||
|
case Scope::Type::AddressDetails:
|
||||||
case Scope::Type::Address:
|
case Scope::Type::Address:
|
||||||
return Lang::Viewer(lng_passport_delete_address);
|
return Lang::Viewer(lng_passport_delete_address);
|
||||||
case Scope::Type::Email:
|
case Scope::Type::Email:
|
||||||
|
@ -700,27 +705,26 @@ bool PanelController::hasValueDocument() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PanelController::hasValueFields() const {
|
bool PanelController::hasValueFields() const {
|
||||||
Expects(_editValue != nullptr);
|
return _editValue && !_editValue->data.parsed.fields.empty();
|
||||||
|
|
||||||
return !_editValue->data.parsed.fields.empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanelController::deleteValue() {
|
void PanelController::deleteValue() {
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editScope != nullptr);
|
||||||
|
Expects(hasValueDocument() || hasValueFields());
|
||||||
|
|
||||||
if (savingScope()) {
|
if (savingScope()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto text = [&] {
|
const auto text = [&] {
|
||||||
switch (_editScope->type) {
|
switch (_editScope->type) {
|
||||||
|
case Scope::Type::PersonalDetails:
|
||||||
|
return lang(lng_passport_delete_details_sure);
|
||||||
case Scope::Type::Identity:
|
case Scope::Type::Identity:
|
||||||
return lang(hasValueDocument()
|
return lang(lng_passport_delete_document_sure);
|
||||||
? lng_passport_delete_document_sure
|
case Scope::Type::AddressDetails:
|
||||||
: lng_passport_delete_details_sure);
|
return lang(lng_passport_delete_address_sure);
|
||||||
case Scope::Type::Address:
|
case Scope::Type::Address:
|
||||||
return lang(hasValueDocument()
|
return lang(lng_passport_delete_document_sure);
|
||||||
? lng_passport_delete_document_sure
|
|
||||||
: lng_passport_delete_address_sure);
|
|
||||||
case Scope::Type::Phone:
|
case Scope::Type::Phone:
|
||||||
return lang(lng_passport_delete_phone_sure);
|
return lang(lng_passport_delete_phone_sure);
|
||||||
case Scope::Type::Email:
|
case Scope::Type::Email:
|
||||||
|
@ -745,7 +749,7 @@ void PanelController::deleteValue() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanelController::deleteValueSure(bool withDetails) {
|
void PanelController::deleteValueSure(bool withDetails) {
|
||||||
Expects(_editValue != nullptr);
|
Expects(!withDetails || _editValue != nullptr);
|
||||||
|
|
||||||
if (hasValueDocument()) {
|
if (hasValueDocument()) {
|
||||||
_form->deleteValueEdit(_editDocument);
|
_form->deleteValueEdit(_editDocument);
|
||||||
|
@ -830,21 +834,22 @@ int PanelController::findNonEmptyDocumentIndex(const Scope &scope) const {
|
||||||
const auto &documents = scope.documents;
|
const auto &documents = scope.documents;
|
||||||
const auto i = ranges::find_if(
|
const auto i = ranges::find_if(
|
||||||
documents,
|
documents,
|
||||||
[&](not_null<const Value*> document) {
|
[](not_null<const Value*> document) {
|
||||||
return document->scansAreFilled(scope.selfieRequired);
|
return document->scansAreFilled();
|
||||||
});
|
});
|
||||||
if (i != end(documents)) {
|
if (i != end(documents)) {
|
||||||
return (i - begin(documents));
|
return (i - begin(documents));
|
||||||
}
|
}
|
||||||
// If we have a document where only selfie is not filled - return it.
|
// If we have a document where only selfie is not filled - return it.
|
||||||
const auto j = ranges::find_if(
|
// #TODO passport half-full value
|
||||||
documents,
|
//const auto j = ranges::find_if(
|
||||||
[&](not_null<const Value*> document) {
|
// documents,
|
||||||
return document->scansAreFilled(false);
|
// [&](not_null<const Value*> document) {
|
||||||
});
|
// return document->scansAreFilled(false);
|
||||||
if (j != end(documents)) {
|
// });
|
||||||
return (j - begin(documents));
|
//if (j != end(documents)) {
|
||||||
}
|
// return (j - begin(documents));
|
||||||
|
//}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -936,8 +941,7 @@ void PanelController::editWithUpload(int index, int documentIndex) {
|
||||||
|
|
||||||
const auto &document = _scopes[index].documents[documentIndex];
|
const auto &document = _scopes[index].documents[documentIndex];
|
||||||
const auto requiresSpecialScan = document->requiresSpecialScan(
|
const auto requiresSpecialScan = document->requiresSpecialScan(
|
||||||
SpecialFile::FrontSide,
|
SpecialFile::FrontSide);
|
||||||
false);
|
|
||||||
const auto allowMany = !requiresSpecialScan;
|
const auto allowMany = !requiresSpecialScan;
|
||||||
const auto widget = _panel->widget();
|
const auto widget = _panel->widget();
|
||||||
EditScans::ChooseScan(widget.get(), [=](QByteArray &&content) {
|
EditScans::ChooseScan(widget.get(), [=](QByteArray &&content) {
|
||||||
|
@ -981,21 +985,26 @@ void PanelController::editScope(int index, int documentIndex) {
|
||||||
&& documentIndex < _scopes[index].documents.size()));
|
&& documentIndex < _scopes[index].documents.size()));
|
||||||
|
|
||||||
_editScope = &_scopes[index];
|
_editScope = &_scopes[index];
|
||||||
_editValue = _editScope->fields;
|
_editValue = _editScope->details;
|
||||||
_editDocument = (documentIndex >= 0)
|
_editDocument = (documentIndex >= 0)
|
||||||
? _scopes[index].documents[documentIndex].get()
|
? _scopes[index].documents[documentIndex].get()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
|
Assert(_editValue || _editDocument);
|
||||||
|
|
||||||
_form->startValueEdit(_editValue);
|
if (_editValue) {
|
||||||
|
_form->startValueEdit(_editValue);
|
||||||
|
}
|
||||||
if (_editDocument) {
|
if (_editDocument) {
|
||||||
_form->startValueEdit(_editDocument);
|
_form->startValueEdit(_editDocument);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto content = [&]() -> object_ptr<Ui::RpWidget> {
|
auto content = [&]() -> object_ptr<Ui::RpWidget> {
|
||||||
|
// #TODO passport pass and display value->error
|
||||||
switch (_editScope->type) {
|
switch (_editScope->type) {
|
||||||
case Scope::Type::Identity:
|
case Scope::Type::Identity:
|
||||||
case Scope::Type::Address: {
|
case Scope::Type::Address: {
|
||||||
auto result = _editDocument
|
Assert(_editDocument != nullptr);
|
||||||
|
auto result = _editValue
|
||||||
? object_ptr<PanelEditDocument>(
|
? object_ptr<PanelEditDocument>(
|
||||||
_panel->widget(),
|
_panel->widget(),
|
||||||
this,
|
this,
|
||||||
|
@ -1007,6 +1016,7 @@ void PanelController::editScope(int index, int documentIndex) {
|
||||||
_editDocument->scanMissingError,
|
_editDocument->scanMissingError,
|
||||||
valueFiles(*_editDocument),
|
valueFiles(*_editDocument),
|
||||||
valueSpecialFiles(*_editDocument))
|
valueSpecialFiles(*_editDocument))
|
||||||
|
// #TODO passport document without details
|
||||||
: object_ptr<PanelEditDocument>(
|
: object_ptr<PanelEditDocument>(
|
||||||
_panel->widget(),
|
_panel->widget(),
|
||||||
this,
|
this,
|
||||||
|
@ -1018,8 +1028,23 @@ void PanelController::editScope(int index, int documentIndex) {
|
||||||
};
|
};
|
||||||
return std::move(result);
|
return std::move(result);
|
||||||
} break;
|
} break;
|
||||||
|
case Scope::Type::PersonalDetails:
|
||||||
|
case Scope::Type::AddressDetails: {
|
||||||
|
Assert(_editValue != nullptr);
|
||||||
|
auto result = object_ptr<PanelEditDocument>(
|
||||||
|
_panel->widget(),
|
||||||
|
this,
|
||||||
|
GetDocumentScheme(_editScope->type),
|
||||||
|
_editValue->data.parsedInEdit);
|
||||||
|
const auto weak = make_weak(result.data());
|
||||||
|
_panelHasUnsavedChanges = [=] {
|
||||||
|
return weak ? weak->hasUnsavedChanges() : false;
|
||||||
|
};
|
||||||
|
return std::move(result);
|
||||||
|
} break;
|
||||||
case Scope::Type::Phone:
|
case Scope::Type::Phone:
|
||||||
case Scope::Type::Email: {
|
case Scope::Type::Email: {
|
||||||
|
Assert(_editValue != nullptr);
|
||||||
const auto &parsed = _editValue->data.parsedInEdit;
|
const auto &parsed = _editValue->data.parsedInEdit;
|
||||||
const auto valueIt = parsed.fields.find("value");
|
const auto valueIt = parsed.fields.find("value");
|
||||||
const auto value = (valueIt == end(parsed.fields)
|
const auto value = (valueIt == end(parsed.fields)
|
||||||
|
@ -1081,16 +1106,12 @@ void PanelController::processValueSaveFinished(
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PanelController::uploadingScopeScan() const {
|
bool PanelController::uploadingScopeScan() const {
|
||||||
Expects(_editValue != nullptr);
|
return (_editValue && _form->uploadingScan(_editValue))
|
||||||
|
|
||||||
return _form->uploadingScan(_editValue)
|
|
||||||
|| (_editDocument && _form->uploadingScan(_editDocument));
|
|| (_editDocument && _form->uploadingScan(_editDocument));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PanelController::savingScope() const {
|
bool PanelController::savingScope() const {
|
||||||
Expects(_editValue != nullptr);
|
return (_editValue && _form->savingValue(_editValue))
|
||||||
|
|
||||||
return _form->savingValue(_editValue)
|
|
||||||
|| (_editDocument && _form->savingValue(_editDocument));
|
|| (_editDocument && _form->savingValue(_editDocument));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1173,7 +1194,7 @@ std::map<SpecialFile, ScanInfo> PanelController::valueSpecialFiles(
|
||||||
SpecialFile::Selfie
|
SpecialFile::Selfie
|
||||||
};
|
};
|
||||||
for (const auto type : types) {
|
for (const auto type : types) {
|
||||||
if (value.requiresSpecialScan(type, _editScope->selfieRequired)) {
|
if (value.requiresSpecialScan(type)) {
|
||||||
const auto i = value.specialScansInEdit.find(type);
|
const auto i = value.specialScansInEdit.find(type);
|
||||||
const auto j = result.emplace(
|
const auto j = result.emplace(
|
||||||
type,
|
type,
|
||||||
|
@ -1190,7 +1211,9 @@ void PanelController::cancelValueEdit() {
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editScope != nullptr);
|
||||||
|
|
||||||
_editScopeBoxes.clear();
|
_editScopeBoxes.clear();
|
||||||
_form->cancelValueEdit(base::take(_editValue));
|
if (const auto value = base::take(_editValue)) {
|
||||||
|
_form->cancelValueEdit(value);
|
||||||
|
}
|
||||||
if (const auto document = base::take(_editDocument)) {
|
if (const auto document = base::take(_editDocument)) {
|
||||||
_form->cancelValueEdit(document);
|
_form->cancelValueEdit(document);
|
||||||
}
|
}
|
||||||
|
@ -1199,7 +1222,6 @@ void PanelController::cancelValueEdit() {
|
||||||
|
|
||||||
void PanelController::saveScope(ValueMap &&data, ValueMap &&filesData) {
|
void PanelController::saveScope(ValueMap &&data, ValueMap &&filesData) {
|
||||||
Expects(_panel != nullptr);
|
Expects(_panel != nullptr);
|
||||||
Expects(_editValue != nullptr);
|
|
||||||
|
|
||||||
if (uploadingScopeScan()) {
|
if (uploadingScopeScan()) {
|
||||||
showToast(lang(lng_passport_wait_upload));
|
showToast(lang(lng_passport_wait_upload));
|
||||||
|
@ -1208,7 +1230,9 @@ void PanelController::saveScope(ValueMap &&data, ValueMap &&filesData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_form->saveValueEdit(_editValue, std::move(data));
|
if (_editValue) {
|
||||||
|
_form->saveValueEdit(_editValue, std::move(data));
|
||||||
|
}
|
||||||
if (_editDocument) {
|
if (_editDocument) {
|
||||||
_form->saveValueEdit(_editDocument, std::move(filesData));
|
_form->saveValueEdit(_editDocument, std::move(filesData));
|
||||||
} else {
|
} else {
|
||||||
|
@ -1219,12 +1243,11 @@ 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 {
|
||||||
Expects(_editValue != nullptr);
|
if (_editValue && _form->editValueChanged(_editValue, data)) {
|
||||||
|
return true;
|
||||||
if (_form->editValueChanged(_editValue, data)) {
|
} else if (_editDocument
|
||||||
|
&& _form->editValueChanged(_editDocument, filesData)) {
|
||||||
return true;
|
return true;
|
||||||
} else if (_editDocument) {
|
|
||||||
return _form->editValueChanged(_editDocument, filesData);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue