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