HaikuDepot: Validate input before creating account

Provide error or info alert when fields are invalid, suggest
providing an email, but allow to ignore the warning.
This commit is contained in:
Stephan Aßmus
2014-10-04 13:31:58 +02:00
parent fa09af9a8f
commit 6f9eb8d1bb
3 changed files with 148 additions and 3 deletions
+141 -3
View File
@@ -19,6 +19,7 @@
#include <PopUpMenu.h>
#include <TabView.h>
#include <TextControl.h>
#include <UnicodeChar.h>
#include "BitmapView.h"
#include "Model.h"
@@ -33,6 +34,7 @@ enum {
MSG_SEND = 'send',
MSG_TAB_SELECTED = 'tbsl',
MSG_CAPTCHA_OBTAINED = 'cpob',
MSG_VALIDATE_FIELDS = 'vldt',
MSG_LANGUAGE_SELECTED = 'lngs',
};
@@ -92,12 +94,13 @@ UserLoginWindow::UserLoginWindow(BWindow* parent, BRect frame, Model& model)
fPasswordField = new BTextControl(B_TRANSLATE("Pass phrase:"), "", NULL);
fPasswordField->TextView()->HideTyping(true);
fNewUsernameField = new BTextControl(B_TRANSLATE("User name:"), "", NULL);
fNewPasswordField = new BTextControl(B_TRANSLATE("Pass phrase:"), "",
fNewUsernameField = new BTextControl(B_TRANSLATE("User name:"), "",
NULL);
fNewPasswordField = new BTextControl(B_TRANSLATE("Pass phrase:"), "",
new BMessage(MSG_VALIDATE_FIELDS));
fNewPasswordField->TextView()->HideTyping(true);
fRepeatPasswordField = new BTextControl(B_TRANSLATE("Repeat pass phrase:"),
"", NULL);
"", new BMessage(MSG_VALIDATE_FIELDS));
fRepeatPasswordField->TextView()->HideTyping(true);
// Construct languages popup
@@ -118,6 +121,19 @@ UserLoginWindow::UserLoginWindow(BWindow* parent, BRect frame, Model& model)
fCaptchaView = new BitmapView("captcha view");
fCaptchaResultField = new BTextControl("", "", NULL);
// Setup modification messages on all text fields to trigger validation
// of input
fNewUsernameField->SetModificationMessage(
new BMessage(MSG_VALIDATE_FIELDS));
fNewPasswordField->SetModificationMessage(
new BMessage(MSG_VALIDATE_FIELDS));
fRepeatPasswordField->SetModificationMessage(
new BMessage(MSG_VALIDATE_FIELDS));
fEmailField->SetModificationMessage(
new BMessage(MSG_VALIDATE_FIELDS));
fCaptchaResultField->SetModificationMessage(
new BMessage(MSG_VALIDATE_FIELDS));
fTabView = new TabView(BMessenger(this),
BMessage(MSG_TAB_SELECTED));
@@ -182,6 +198,10 @@ void
UserLoginWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case MSG_VALIDATE_FIELDS:
_ValidateCreateAccountFields();
break;
case MSG_SEND:
switch (fMode) {
case LOGIN:
@@ -220,6 +240,7 @@ UserLoginWindow::MessageReceived(BMessage* message)
} else {
fCaptchaView->SetBitmap(NULL);
}
fCaptchaResultField->SetText("");
break;
case MSG_LANGUAGE_SELECTED:
@@ -262,6 +283,7 @@ UserLoginWindow::_SetMode(Mode mode)
if (fCaptchaToken.IsEmpty())
_RequestCaptcha();
fNewUsernameField->MakeFocus();
_ValidateCreateAccountFields();
break;
default:
break;
@@ -269,6 +291,119 @@ UserLoginWindow::_SetMode(Mode mode)
}
static int32
count_digits(const BString& string)
{
int32 digits = 0;
const char* c = string.String();
for (int32 i = 0; i < string.CountChars(); i++) {
uint32 unicodeChar = BUnicodeChar::FromUTF8(&c);
if (BUnicodeChar::IsDigit(unicodeChar))
digits++;
}
return digits;
}
static int32
count_upper_case_letters(const BString& string)
{
int32 upperCaseLetters = 0;
const char* c = string.String();
for (int32 i = 0; i < string.CountChars(); i++) {
uint32 unicodeChar = BUnicodeChar::FromUTF8(&c);
if (BUnicodeChar::IsUpper(unicodeChar))
upperCaseLetters++;
}
return upperCaseLetters;
}
bool
UserLoginWindow::_ValidateCreateAccountFields(bool alertProblems)
{
BString nickName(fNewUsernameField->Text());
BString password1(fNewPasswordField->Text());
BString password2(fRepeatPasswordField->Text());
BString email(fEmailField->Text());
BString captcha(fCaptchaResultField->Text());
// TODO: Use the same validation as the web-serivce
bool validUserName = nickName.Length() >= 3;
fNewUsernameField->MarkAsInvalid(validUserName);
bool validPassword = password1.Length() >= 8
&& count_digits(password1) >= 2
&& count_upper_case_letters(password1) >= 2;
fNewPasswordField->MarkAsInvalid(!validPassword);
fRepeatPasswordField->MarkAsInvalid(password1 != password2);
bool validCaptcha = captcha.Length() > 0;
fCaptchaResultField->MarkAsInvalid(!validCaptcha);
bool valid = validUserName && validPassword && password1 == password2
&& validCaptcha;
if (valid && email.Length() > 0)
return true;
if (alertProblems) {
BString message;
alert_type alertType;
const char* okLabel = B_TRANSLATE("OK");
const char* cancelLabel = NULL;
if (!valid) {
message = B_TRANSLATE("There are problems in the form:\n\n");
alertType = B_WARNING_ALERT;
} else {
alertType = B_IDEA_ALERT;
okLabel = B_TRANSLATE("Ignore");
cancelLabel = B_TRANSLATE("Cancel");
}
if (!validUserName) {
message << B_TRANSLATE(
"The user name needs to be at least "
"3 letters long.") << "\n\n";
}
if (!validPassword) {
message << B_TRANSLATE(
"The password is too weak or invalid. "
"Please use at least 8 characters with "
"at least 2 numbers and 2 upper-case "
"letters.") << "\n\n";
}
if (password1 != password2) {
message << B_TRANSLATE(
"The passwords do not match.") << "\n\n";
}
if (email.Length() == 0) {
message << B_TRANSLATE(
"If you do not provide an email address, "
"you will not be able to reset your password "
"if you forget it.") << "\n\n";
}
if (!validCaptcha) {
message << B_TRANSLATE(
"The captcha puzzle needs to be solved.") << "\n\n";
}
BAlert* alert = new(std::nothrow) BAlert(
B_TRANSLATE("Input validation"),
message,
okLabel, cancelLabel, NULL,
B_WIDTH_AS_USUAL, alertType);
if (alert != NULL) {
int32 choice = alert->Go();
if (choice == 1)
return false;
}
}
return valid;
}
void
UserLoginWindow::_Login()
{
@@ -287,6 +422,9 @@ UserLoginWindow::_Login()
void
UserLoginWindow::_CreateAccount()
{
if (!_ValidateCreateAccountFields(true))
return;
BAutolock locker(&fLock);
if (fWorkerThread >= 0)
+2
View File
@@ -40,6 +40,8 @@ private:
};
void _SetMode(Mode mode);
bool _ValidateCreateAccountFields(
bool alertProblems = false);
void _Login();
void _CreateAccount();
void _RequestCaptcha();
+5
View File
@@ -336,10 +336,15 @@ BTextControl::Text() const
void
BTextControl::MarkAsInvalid(bool invalid)
{
uint32 look = fLook;
if (invalid)
fLook |= BControlLook::B_INVALID;
else
fLook &= ~BControlLook::B_INVALID;
if (look != fLook)
Invalidate();
}