mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-04-09 03:01:36 +00:00
Improve name/postcode validation.
This commit is contained in:
parent
6aecb81c23
commit
308fb19da4
@ -1591,6 +1591,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
"lng_passport_gender_male" = "Male";
|
"lng_passport_gender_male" = "Male";
|
||||||
"lng_passport_gender_female" = "Female";
|
"lng_passport_gender_female" = "Female";
|
||||||
"lng_passport_country" = "Country";
|
"lng_passport_country" = "Country";
|
||||||
|
"lng_passport_residence_country" = "Residence";
|
||||||
"lng_passport_country_choose" = "Choose country";
|
"lng_passport_country_choose" = "Choose country";
|
||||||
"lng_passport_document_number" = "Card Number";
|
"lng_passport_document_number" = "Card Number";
|
||||||
"lng_passport_expiry_date" = "Expiry date";
|
"lng_passport_expiry_date" = "Expiry date";
|
||||||
|
@ -839,23 +839,22 @@ bool Messenger::openLocalUrl(const QString &url) {
|
|||||||
auto command = urlTrimmed.midRef(qstr("tg://").size());
|
auto command = urlTrimmed.midRef(qstr("tg://").size());
|
||||||
|
|
||||||
const auto showPassportForm = [](const QMap<QString, QString> ¶ms) {
|
const auto showPassportForm = [](const QMap<QString, QString> ¶ms) {
|
||||||
if (const auto botId = params.value("bot_id", QString()).toInt()) {
|
const auto botId = params.value("bot_id", QString()).toInt();
|
||||||
const auto scope = params.value("scope", QString());
|
const auto scope = params.value("scope", QString());
|
||||||
const auto callback = params.value("callback_url", QString());
|
const auto callback = params.value("callback_url", QString());
|
||||||
const auto publicKey = params.value("public_key", QString());
|
const auto publicKey = params.value("public_key", QString());
|
||||||
const auto payload = params.value("payload", QString());
|
const auto payload = params.value("payload", QString());
|
||||||
const auto errors = params.value("errors", QString());
|
const auto errors = params.value("errors", QString());
|
||||||
if (const auto window = App::wnd()) {
|
if (const auto window = App::wnd()) {
|
||||||
if (const auto controller = window->controller()) {
|
if (const auto controller = window->controller()) {
|
||||||
controller->showPassportForm(Passport::FormRequest(
|
controller->showPassportForm(Passport::FormRequest(
|
||||||
botId,
|
botId,
|
||||||
scope,
|
scope,
|
||||||
callback,
|
callback,
|
||||||
publicKey,
|
publicKey,
|
||||||
payload,
|
payload,
|
||||||
errors));
|
errors));
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -158,7 +158,7 @@ QString ComputeScopeRowReadyString(const Scope &scope) {
|
|||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
const auto text = i->second.text;
|
const auto text = i->second.text;
|
||||||
if (row.validate && !row.validate(text)) {
|
if (row.error && row.error(text).has_value()) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
pushListValue(format ? format(text) : text);
|
pushListValue(format ? format(text) : text);
|
||||||
@ -170,7 +170,7 @@ QString ComputeScopeRowReadyString(const Scope &scope) {
|
|||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
const auto text = i->second.text;
|
const auto text = i->second.text;
|
||||||
if (row.validate && !row.validate(text)) {
|
if (row.error && row.error(text).has_value()) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
pushListValue(text);
|
pushListValue(text);
|
||||||
|
@ -28,8 +28,7 @@ constexpr auto kMaxDocumentSize = 24;
|
|||||||
constexpr auto kMaxStreetSize = 64;
|
constexpr auto kMaxStreetSize = 64;
|
||||||
constexpr auto kMinCitySize = 2;
|
constexpr auto kMinCitySize = 2;
|
||||||
constexpr auto kMaxCitySize = 64;
|
constexpr auto kMaxCitySize = 64;
|
||||||
constexpr auto kMinPostcodeSize = 2;
|
constexpr auto kMaxPostcodeSize = 10;
|
||||||
constexpr auto kMaxPostcodeSize = 12;
|
|
||||||
|
|
||||||
EditDocumentScheme GetDocumentScheme(
|
EditDocumentScheme GetDocumentScheme(
|
||||||
Scope::Type type,
|
Scope::Type type,
|
||||||
@ -50,32 +49,53 @@ EditDocumentScheme GetDocumentScheme(
|
|||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
const auto DontValidate = nullptr;
|
const auto DontValidate = nullptr;
|
||||||
const auto LimitedValidate = [](int max, int min = 1) {
|
const auto FromBoolean = [](auto validation) {
|
||||||
return [=](const QString &value) {
|
return [=](const QString &value) {
|
||||||
return (value.size() >= min) && (value.size() <= max);
|
return validation(value)
|
||||||
|
? base::none
|
||||||
|
: base::make_optional(QString());
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
const auto NameValidate = LimitedValidate(kMaxNameSize);
|
const auto LimitedValidate = [=](int max, int min = 1) {
|
||||||
|
return FromBoolean([=](const QString &value) {
|
||||||
|
return (value.size() >= min) && (value.size() <= max);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
using Result = base::optional<QString>;
|
||||||
|
const auto NameValidate = [](const QString &value) -> Result {
|
||||||
|
if (value.isEmpty() || value.size() > kMaxNameSize) {
|
||||||
|
return QString();
|
||||||
|
} else if (!QRegularExpression(
|
||||||
|
"^[a-zA-Z\\- ]+$"
|
||||||
|
).match(value).hasMatch()) {
|
||||||
|
return "Use latin characters only.";// lang(lng_passport_bad_name);
|
||||||
|
}
|
||||||
|
return base::none;
|
||||||
|
};
|
||||||
|
|
||||||
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);
|
||||||
const auto PostcodeValidate = LimitedValidate(
|
const auto PostcodeValidate = FromBoolean([](const QString &value) {
|
||||||
kMaxPostcodeSize,
|
return QRegularExpression(
|
||||||
kMinPostcodeSize);
|
QString("^[a-zA-Z0-9\\-]{2,%1}$").arg(kMaxPostcodeSize)
|
||||||
const auto DateValidate = [](const QString &value) {
|
).match(value).hasMatch();
|
||||||
|
});
|
||||||
|
const auto DateValidateBoolean = [](const QString &value) {
|
||||||
return QRegularExpression(
|
return QRegularExpression(
|
||||||
"^\\d{2}\\.\\d{2}\\.\\d{4}$"
|
"^\\d{2}\\.\\d{2}\\.\\d{4}$"
|
||||||
).match(value).hasMatch();
|
).match(value).hasMatch();
|
||||||
};
|
};
|
||||||
const auto DateOrEmptyValidate = [=](const QString &value) {
|
const auto DateValidate = FromBoolean(DateValidateBoolean);
|
||||||
return value.isEmpty() || DateValidate(value);
|
const auto DateOrEmptyValidate = FromBoolean([=](const QString &value) {
|
||||||
};
|
return value.isEmpty() || DateValidateBoolean(value);
|
||||||
const auto GenderValidate = [](const QString &value) {
|
});
|
||||||
|
const auto GenderValidate = FromBoolean([](const QString &value) {
|
||||||
return value == qstr("male") || value == qstr("female");
|
return value == qstr("male") || value == qstr("female");
|
||||||
};
|
});
|
||||||
const auto CountryValidate = [=](const QString &value) {
|
const auto CountryValidate = FromBoolean([=](const QString &value) {
|
||||||
return !CountryFormat(value).isEmpty();
|
return !CountryFormat(value).isEmpty();
|
||||||
};
|
});
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Scope::Type::Identity: {
|
case Scope::Type::Identity: {
|
||||||
@ -142,6 +162,14 @@ EditDocumentScheme GetDocumentScheme(
|
|||||||
CountryValidate,
|
CountryValidate,
|
||||||
CountryFormat,
|
CountryFormat,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ValueClass::Fields,
|
||||||
|
PanelDetailsType::Country,
|
||||||
|
qsl("residence_country_code"),
|
||||||
|
lang(lng_passport_residence_country),
|
||||||
|
CountryValidate,
|
||||||
|
CountryFormat,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
ValueClass::Scans,
|
ValueClass::Scans,
|
||||||
PanelDetailsType::Text,
|
PanelDetailsType::Text,
|
||||||
@ -234,7 +262,7 @@ EditDocumentScheme GetDocumentScheme(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
ValueClass::Fields,
|
ValueClass::Fields,
|
||||||
PanelDetailsType::Text,
|
PanelDetailsType::Postcode,
|
||||||
qsl("post_code"),
|
qsl("post_code"),
|
||||||
lang(lng_passport_postcode),
|
lang(lng_passport_postcode),
|
||||||
PostcodeValidate,
|
PostcodeValidate,
|
||||||
|
@ -22,9 +22,60 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
namespace Passport {
|
namespace Passport {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
class TextRow : public PanelDetailsRow {
|
class PostcodeInput : public Ui::MaskedInputField {
|
||||||
public:
|
public:
|
||||||
TextRow(
|
PostcodeInput(
|
||||||
|
QWidget *parent,
|
||||||
|
const style::InputField &st,
|
||||||
|
base::lambda<QString()> placeholderFactory,
|
||||||
|
const QString &val);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void correctValue(
|
||||||
|
const QString &was,
|
||||||
|
int wasCursor,
|
||||||
|
QString &now,
|
||||||
|
int &nowCursor) override;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
PostcodeInput::PostcodeInput(
|
||||||
|
QWidget *parent,
|
||||||
|
const style::InputField &st,
|
||||||
|
base::lambda<QString()> placeholderFactory,
|
||||||
|
const QString &val)
|
||||||
|
: MaskedInputField(parent, st, std::move(placeholderFactory), val) {
|
||||||
|
if (!QRegularExpression("^[a-zA-Z0-9\\-]+$").match(val).hasMatch()) {
|
||||||
|
setText(QString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostcodeInput::correctValue(
|
||||||
|
const QString &was,
|
||||||
|
int wasCursor,
|
||||||
|
QString &now,
|
||||||
|
int &nowCursor) {
|
||||||
|
QString newText;
|
||||||
|
newText.reserve(now.size());
|
||||||
|
auto newPos = nowCursor;
|
||||||
|
for (auto i = 0, l = now.size(); i < l; ++i) {
|
||||||
|
const auto ch = now[i];
|
||||||
|
if ((ch >= '0' && ch <= '9')
|
||||||
|
|| (ch >= 'a' && ch <= 'z')
|
||||||
|
|| (ch >= 'A' && ch <= 'Z')
|
||||||
|
|| (ch == '-')) {
|
||||||
|
newText.append(ch);
|
||||||
|
} else if (i < nowCursor) {
|
||||||
|
--newPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setCorrectedText(now, nowCursor, newText, newPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Input>
|
||||||
|
class AbstractTextRow : public PanelDetailsRow {
|
||||||
|
public:
|
||||||
|
AbstractTextRow(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
const QString &label,
|
const QString &label,
|
||||||
const QString &value,
|
const QString &value,
|
||||||
@ -39,7 +90,7 @@ private:
|
|||||||
void showInnerError() override;
|
void showInnerError() override;
|
||||||
void finishInnerAnimating() override;
|
void finishInnerAnimating() override;
|
||||||
|
|
||||||
object_ptr<Ui::InputField> _field;
|
object_ptr<Input> _field;
|
||||||
rpl::variable<QString> _value;
|
rpl::variable<QString> _value;
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -192,7 +243,8 @@ private:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
TextRow::TextRow(
|
template <typename Input>
|
||||||
|
AbstractTextRow<Input>::AbstractTextRow(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
const QString &label,
|
const QString &label,
|
||||||
const QString &value,
|
const QString &value,
|
||||||
@ -201,34 +253,40 @@ TextRow::TextRow(
|
|||||||
, _field(this, st::passportDetailsField, nullptr, value)
|
, _field(this, st::passportDetailsField, nullptr, value)
|
||||||
, _value(value) {
|
, _value(value) {
|
||||||
_field->setMaxLength(limit);
|
_field->setMaxLength(limit);
|
||||||
connect(_field, &Ui::InputField::changed, [=] {
|
connect(_field, &Input::changed, [=] {
|
||||||
_value = valueCurrent();
|
_value = valueCurrent();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextRow::setFocusFast() {
|
template <typename Input>
|
||||||
|
bool AbstractTextRow<Input>::setFocusFast() {
|
||||||
_field->setFocusFast();
|
_field->setFocusFast();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TextRow::valueCurrent() const {
|
template <typename Input>
|
||||||
|
QString AbstractTextRow<Input>::valueCurrent() const {
|
||||||
return _field->getLastText();
|
return _field->getLastText();
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<QString> TextRow::value() const {
|
template <typename Input>
|
||||||
|
rpl::producer<QString> AbstractTextRow<Input>::value() const {
|
||||||
return _value.value();
|
return _value.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
int TextRow::resizeInner(int left, int top, int width) {
|
template <typename Input>
|
||||||
|
int AbstractTextRow<Input>::resizeInner(int left, int top, int width) {
|
||||||
_field->setGeometry(left, top, width, _field->height());
|
_field->setGeometry(left, top, width, _field->height());
|
||||||
return st::semiboldFont->height;
|
return st::semiboldFont->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextRow::showInnerError() {
|
template <typename Input>
|
||||||
|
void AbstractTextRow<Input>::showInnerError() {
|
||||||
_field->showError();
|
_field->showError();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextRow::finishInnerAnimating() {
|
template <typename Input>
|
||||||
|
void AbstractTextRow<Input>::finishInnerAnimating() {
|
||||||
_field->finishAnimating();
|
_field->finishAnimating();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -905,7 +963,17 @@ object_ptr<PanelDetailsRow> PanelDetailsRow::Create(
|
|||||||
auto result = [&]() -> object_ptr<PanelDetailsRow> {
|
auto result = [&]() -> object_ptr<PanelDetailsRow> {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Type::Text:
|
case Type::Text:
|
||||||
return object_ptr<TextRow>(parent, label, value, limit);
|
return object_ptr<AbstractTextRow<Ui::InputField>>(
|
||||||
|
parent,
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
limit);
|
||||||
|
case Type::Postcode:
|
||||||
|
return object_ptr<AbstractTextRow<PostcodeInput>>(
|
||||||
|
parent,
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
limit);
|
||||||
case Type::Country:
|
case Type::Country:
|
||||||
return object_ptr<CountryRow>(parent, controller, label, value);
|
return object_ptr<CountryRow>(parent, controller, label, value);
|
||||||
case Type::Gender:
|
case Type::Gender:
|
||||||
@ -944,7 +1012,7 @@ int PanelDetailsRow::resizeGetHeight(int newWidth) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanelDetailsRow::showError(const QString &error) {
|
void PanelDetailsRow::showError(base::optional<QString> error) {
|
||||||
if (!_errorHideSubscription) {
|
if (!_errorHideSubscription) {
|
||||||
_errorHideSubscription = true;
|
_errorHideSubscription = true;
|
||||||
|
|
||||||
@ -955,17 +1023,24 @@ void PanelDetailsRow::showError(const QString &error) {
|
|||||||
}
|
}
|
||||||
showInnerError();
|
showInnerError();
|
||||||
startErrorAnimation(true);
|
startErrorAnimation(true);
|
||||||
if (!error.isEmpty()) {
|
if (!error.has_value()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (error->isEmpty()) {
|
||||||
|
if (_error) {
|
||||||
|
_error->hide(anim::type::normal);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (!_error) {
|
if (!_error) {
|
||||||
_error.create(
|
_error.create(
|
||||||
this,
|
this,
|
||||||
object_ptr<Ui::FlatLabel>(
|
object_ptr<Ui::FlatLabel>(
|
||||||
this,
|
this,
|
||||||
error,
|
*error,
|
||||||
Ui::FlatLabel::InitType::Simple,
|
Ui::FlatLabel::InitType::Simple,
|
||||||
st::passportVerifyErrorLabel));
|
st::passportVerifyErrorLabel));
|
||||||
} else {
|
} else {
|
||||||
_error->entity()->setText(error);
|
_error->entity()->setText(*error);
|
||||||
}
|
}
|
||||||
_error->heightValue(
|
_error->heightValue(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
|
@ -25,6 +25,7 @@ class PanelController;
|
|||||||
|
|
||||||
enum class PanelDetailsType {
|
enum class PanelDetailsType {
|
||||||
Text,
|
Text,
|
||||||
|
Postcode,
|
||||||
Country,
|
Country,
|
||||||
Date,
|
Date,
|
||||||
Gender,
|
Gender,
|
||||||
@ -65,7 +66,7 @@ public:
|
|||||||
virtual bool setFocusFast();
|
virtual bool setFocusFast();
|
||||||
virtual rpl::producer<QString> value() const = 0;
|
virtual rpl::producer<QString> value() const = 0;
|
||||||
virtual QString valueCurrent() const = 0;
|
virtual QString valueCurrent() const = 0;
|
||||||
void showError(const QString &error);
|
void showError(base::optional<QString> error = base::none);
|
||||||
bool errorShown() const;
|
bool errorShown() const;
|
||||||
void hideError();
|
void hideError();
|
||||||
void finishAnimating();
|
void finishAnimating();
|
||||||
|
@ -419,10 +419,14 @@ bool PanelEditDocument::validate() {
|
|||||||
auto first = QPointer<PanelDetailsRow>();
|
auto first = QPointer<PanelDetailsRow>();
|
||||||
for (const auto [i, field] : base::reversed(_details)) {
|
for (const auto [i, field] : base::reversed(_details)) {
|
||||||
const auto &row = _scheme.rows[i];
|
const auto &row = _scheme.rows[i];
|
||||||
if (field->errorShown()
|
if (field->errorShown()) {
|
||||||
|| (row.validate && !row.validate(field->valueCurrent()))) {
|
field->showError();
|
||||||
field->showError(QString());
|
|
||||||
first = field;
|
first = field;
|
||||||
|
} else if (row.error) {
|
||||||
|
if (const auto error = row.error(field->valueCurrent())) {
|
||||||
|
field->showError(error);
|
||||||
|
first = field;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (error) {
|
if (error) {
|
||||||
|
@ -43,7 +43,7 @@ struct EditDocumentScheme {
|
|||||||
PanelDetailsType inputType = PanelDetailsType();
|
PanelDetailsType inputType = PanelDetailsType();
|
||||||
QString key;
|
QString key;
|
||||||
QString label;
|
QString label;
|
||||||
base::lambda<bool(const QString &value)> validate;
|
base::lambda<base::optional<QString>(const QString &value)> error;
|
||||||
base::lambda<QString(const QString &value)> format;
|
base::lambda<QString(const QString &value)> format;
|
||||||
int lengthLimit = 0;
|
int lengthLimit = 0;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user