diff --git a/public/api/Dictionary.php b/public/api/Dictionary.php index 23e9c72..b1622d0 100644 --- a/public/api/Dictionary.php +++ b/public/api/Dictionary.php @@ -33,11 +33,11 @@ class Dictionary { if ($insert_dictionary === true) { $new_dictionary_id = $this->db->lastInsertId(); - $insert_linguistics_query = "INSERT INTO dictionary_linguistics (dictionary, partsOfSpeech, phonology) + $insert_linguistics_query = "INSERT INTO dictionary_linguistics (dictionary, parts_of_speech, phonology) VALUES ($new_dictionary_id, ?, ?)"; $insert_linguistics = $this->db->execute($insert_linguistics_query, array( json_encode($this->defaults['partsOfSpeech']), - json_encode($this->defaults['phonotactics']), + json_encode($this->defaults['phonology']), )); if ($insert_linguistics === true) { diff --git a/public/api/User.php b/public/api/User.php index bc9a97d..fbcded5 100644 --- a/public/api/User.php +++ b/public/api/User.php @@ -13,8 +13,8 @@ class User { } public function logIn ($email, $password) { - $query = 'SELECT * FROM users WHERE email=?'; - $user = $this->db->query($query, array($email))->fetch(); + $query = 'SELECT * FROM users WHERE email=:email OR username=:email'; + $user = $this->db->query($query, array(':email' => $email))->fetch(); if ($user) { if ($user['old_password'] !== null) { if ($user['old_password'] === crypt($password, $email)) { @@ -23,6 +23,7 @@ class User { } } } else if (password_verify($password, $user['password'])) { + $this->db->execute('UPDATE users SET last_login=' . time() . ' WHERE id=' . $user['id']); return $this->generateUserToken($user['id'], $user['current_dictionary']); } } @@ -41,11 +42,18 @@ class User { return $user->rowCount() > 0; } - public function create ($email, $password) { - $insert_user_query = 'INSERT INTO users (email, password) VALUES (?, ?)'; + public function create ($email, $password, $user_data) { + $insert_user_query = 'INSERT INTO users (email, password, public_name, username, allow_email, created_on) +VALUES (?, ?, ?, ?, ?, '. time() .')'; $password_hash = password_hash($password, PASSWORD_DEFAULT); - $insert_user = $this->db->execute($insert_user_query, array($email, $password_hash)); + $insert_user = $this->db->execute($insert_user_query, array( + $email, + $password_hash, + $user_data['publicName'] !== '' ? $user_data['publicName'] : null, + $user_data['username'] !== '' ? $user_data['username'] : null, + $user_data['allowEmail'] ? 1 : 0, + )); if ($insert_user === true) { $new_user_id = $this->db->lastInsertId(); diff --git a/public/api/index.php b/public/api/index.php index 8247fc0..6a96fc8 100644 --- a/public/api/index.php +++ b/public/api/index.php @@ -33,7 +33,7 @@ switch ($action) { if (isset($request['email']) && isset($request['password'])) { $user = new User(); if (!$user->emailExists($request['email'])) { - $token = $user->create($request['email'], $request['password']); + $token = $user->create($request['email'], $request['password'], $request['userData']); if ($token !== false) { return Response::json(array( 'data' => $token, diff --git a/src/components/management/AccountManager/LoginForm.jsx b/src/components/management/AccountManager/LoginForm.jsx index 1efbd8d..7b6dbf0 100644 --- a/src/components/management/AccountManager/LoginForm.jsx +++ b/src/components/management/AccountManager/LoginForm.jsx @@ -24,6 +24,7 @@ export class LoginForm extends Component { loginPassword: '', loginEmailError: '', loginPasswordError: '', + loginFormIsValid: true, signupEmail: '', signupUsername: '', signupPublicName: '', @@ -38,48 +39,104 @@ export class LoginForm extends Component { signupUsernameChecking: false, signupEmailIsUnique: true, signupUsernameIsUnique: true, + signupFormIsValid: true, }; } + get loginFormIsValid () { + const { + loginEmailError, + loginPasswordError, + } = this.state; + return loginEmailError === '' && loginPasswordError === ''; + } + + get signupFormIsValid () { + const { + signupEmailError, + signupEmailChecking, + signupEmailIsUnique, + signupUsernameError, + signupUsernameChecking, + signupUsernameIsUnique, + signupPasswordError, + signupConfirmError, + } = this.state; + return !signupEmailChecking && !signupUsernameChecking + && signupEmailIsUnique && signupUsernameIsUnique + && signupEmailError === '' && signupUsernameError === '' + && signupPasswordError === '' && signupConfirmError === ''; + } + changeTab (tab) { this.setState({ visibleTab: tab }); } updateField (field, event) { - const requiredFields = ['loginEmail', 'loginPassword', 'signupEmail', 'signupPassword', 'signupConfirm']; const {value, checked} = event.target; const fieldUpdate = {}; + const fieldErrors = this.validateField(field, value); + fieldUpdate[field] = (field === 'signupAllowEmail') ? checked : value; + this.setState(Object.assign(fieldUpdate, fieldErrors)); + } + + validateField (field, value) { + const fieldErrors = {}; const errorFieldName = `${field}Error`; let isValid = true; + const requiredFields = ['loginEmail', 'loginPassword', 'signupEmail', 'signupPassword', 'signupConfirm']; if (requiredFields.includes(field)) { if (value === '') { isValid = false; - fieldUpdate[errorFieldName] = 'This field must not be blank'; - } else if (field.includes('Email') && !/.+@.+/g.test(value)) { + fieldErrors[errorFieldName] = 'This field must not be blank'; + } else if (field === 'signupEmail' && !/.+@.+/g.test(value)) { isValid = false; - fieldUpdate[errorFieldName] = 'The email address you entered looks wrong'; + fieldErrors[errorFieldName] = 'The email address you entered looks wrong'; } else if (field === 'signupPassword' && value.length < 6) { isValid = false; - fieldUpdate[errorFieldName] = 'Please make your password at least 6 characters long'; - } else if ((field === 'signupPassword' && value !== this.state.signupConfirm) - || (field === 'signupConfirm' && value !== this.state.signupPassword)) { + fieldErrors[errorFieldName] = 'Please make your password at least 6 characters long'; + } else if (field === 'signupConfirm' && value !== this.state.signupPassword) { isValid = false; - fieldUpdate[errorFieldName] = 'Your passwords must match'; + fieldErrors[errorFieldName] = 'Your passwords must match'; } } if (field === 'signupUsername') { if (value !== '' && /[^a-zA-Z0-9]+/g.test(value)) { isValid = false; - fieldUpdate[errorFieldName] = 'Please use only letters and numbers'; + fieldErrors[errorFieldName] = 'Please use only letters and numbers'; } } if (isValid) { - fieldUpdate[errorFieldName] = ''; + fieldErrors[errorFieldName] = ''; } - fieldUpdate[field] = (field === 'signupAllowEmail') ? checked : value; - this.setState(fieldUpdate); + return fieldErrors; + } + + validateSignupForm (callback) { + const fields = ['signupEmail', 'signupUsername', 'signupPassword', 'signupConfirm']; + let errors = {}; + fields.forEach(field => { + const fieldErrors = this.validateField(field, this.state[field]); + errors = Object.assign(errors, fieldErrors); + }); + errors.signupFormIsValid = !signupEmailChecking && !signupUsernameChecking + && signupEmailIsUnique && signupUsernameIsUnique + && Object.keys(errors).every(field => errors[field] === ''); + this.setState(errors, callback); + } + + validateLoginForm (callback) { + const fields = ['loginEmail','loginPassword']; + let errors = {}; + fields.forEach(field => { + errors = Object.assign(errors, this.validateField(field, this.state[field])); + }); + errors.loginFormIsValid = Object.keys(errors).every(field => { + return errors[field] === ''; + }); + this.setState(errors, callback); } checkFieldUnique (field, event) { @@ -117,6 +174,34 @@ export class LoginForm extends Component { } } + logIn () { + this.validateLoginForm(() => { + if (this.loginFormIsValid) { + const { loginEmail, loginPassword } = this.state; + this.props.logIn(loginEmail, loginPassword); + } + }); + } + + createAccount () { + this.validateSignupForm(() => { + if (this.signupFormIsValid) { + const { + signupEmail, + signupUsername, + signupPublicName, + signupPassword, + signupAllowEmail + } = this.state; + this.props.signUp(signupEmail, signupPassword, { + username: signupUsername, + publicName: signupPublicName, + allowEmail: signupAllowEmail, + }); + } + }); + } + render () { return (
@@ -137,7 +222,7 @@ export class LoginForm extends Component {
{this.state.visibleTab === 'login' ? ( -
+

Log In

@@ -146,7 +231,16 @@ export class LoginForm extends Component { Email/Username
- + this.updateField('loginEmail', event)} /> + { + this.state.loginEmailError !== '' + ? ( +
+ {this.state.loginEmailError} +
+ ) : null + }
@@ -154,12 +248,28 @@ export class LoginForm extends Component { Password
- + this.updateField('loginPassword', event)} + onChange={this.validateLoginForm.bind(this)} /> + { + this.state.loginPasswordError !== '' + ? ( +
+ {this.state.loginPasswordError} +
+ ) : null + }
+
+ + Log In + +
) : ( -
+

Create a New Account

@@ -285,6 +395,14 @@ export class LoginForm extends Component {
+
+
+ + Create Account + +
+
diff --git a/src/components/management/AccountManager/index.jsx b/src/components/management/AccountManager/index.jsx index f93c0c7..1b596c9 100644 --- a/src/components/management/AccountManager/index.jsx +++ b/src/components/management/AccountManager/index.jsx @@ -23,17 +23,7 @@ export class AccountManager extends Component { } logIn (email, password) { - return request('login', { email, password }, response => { - const { data, error } = response; - if (error) { - console.error(data); - } else { - store.set('LexicongaToken', data); - this.setState({ isLoggedIn: true }, () => { - this.props.updater.sync(); - }); - } - }); + return request('login', { email, password }, this.handleResponse.bind(this)); } logOut () { @@ -41,6 +31,26 @@ export class AccountManager extends Component { this.setState({ isLoggedIn: false }); } + signUp (email, password, userData) { + request('create-account', { + email, + password, + userData, + }, this.handleResponse.bind(this)); + } + + handleResponse (response) { + const { data, error } = response; + if (error) { + console.error(data); + } else { + store.set('LexicongaToken', data); + this.setState({ isLoggedIn: true }, () => { + this.props.updater.sync(); + }); + } + } + render () { const token = store.get('LexicongaToken'); @@ -60,7 +70,7 @@ export class AccountManager extends Component { } return ( - {}} /> + ); } diff --git a/src/components/structure/Header.jsx b/src/components/structure/Header.jsx index 9149622..ed5b6c7 100644 --- a/src/components/structure/Header.jsx +++ b/src/components/structure/Header.jsx @@ -48,10 +48,10 @@ export class Header extends Component {
- + - +