Files
habitica/website/client/components/auth/authForm.vue
Phillip Thelen ebf3b4aa47 Username announcement (#10729)
* Change update username API call

The call no longer requires a password and also validates the username.

* Implement API call to verify username without setting it

* Improve coding style

* Apply username verification to registration

* Update error messages

* Validate display names.

* Fix API early Stat Point allocation (#10680)

* Refactor hasClass check to common so it can be used in shared & server-side code

* Check that user has selected class before allocating stat points

* chore(event): end Ember Hatching Potions

* chore(analytics): reenable navigation tracking

* update bcrypt

* Point achievement modal links to main site (#10709)

* Animal ears after death (#10691)

* Animal Ears purchasable with Gold if lost in Death

* remove ears from pinned items when set is bought

* standardise css and error handling for gems and coins

* revert accidental new line

* fix client tests

* Reduce margin-bottom of checklist-item from 10px to -3px. (#10684)

* chore(i18n): update locales

* 4.61.1

* feat(content): Subscriber Items and Magic Potions

* chore(sprites): compile

* chore(i18n): update locales

* 4.62.0

* Display notification for users to confirm their username

* fix typo

* WIP(usernames): Changes to address #10694

* WIP(usernames): Further changes for #10694

* fix(usernames): don't show spurious headings

* Change verify username notification to new version

* Improve feedback for invalid usernames

* Allow user to set their username again to confirm it

* Improve validation display for usernames

* Temporarily move display name validation outside of schema

* Improve rendering banner about sleeping in the inn

See #10695

* Display settings in one column

* Position inn banner when window is resized

* Update inn banner handling

* Fix banner offset on initial load

* Fix minor issues.

* Issue: 10660 - Fixed. Changed default to Please Enter A Value (#10718)

* Issue: 10660 - Fixed. Changed default to Please Enter A Value

* Issue: 10660 - Fixed/revision 2 Changed default to Enter A Value

* chore(news): Bailey announcements

* chore(i18n): update locales

* 4.62.1

* adjust wiki link for usernameInfo string

https://github.com/HabitRPG/habitica-private/issues/7#issuecomment-425405425

* raise coverage for tasks api calls (#10029)

* - updates a group task - approval is required
- updates a group task with checklist

* add expect to test the new checklist length

* - moves tasks to a specified position out of length

* remove unused line

* website getter tasks tests

* re-add sanitizeUserChallengeTask

* change config.json.example variable to be a string not a boolean

* fix tests - pick the text / up/down props too

* fix test - remove changes on text/up/down - revert sanitize condition - revert sanitization props

* Change update username API call

The call no longer requires a password and also validates the username.

* feat(content): Subscriber Items and Magic Potions

* Re-add register call

* Fix merge issue

* Fix issue with setting username

* Implement new alert style

* Display username confirmation status in settings

* Add disclaimer to change username field

* validate username in settings

* Allow specific fields to be focused when opening site settings

* Implement requested changes.

* Fix merge issue

* Fix failing tests

* verify username when users register with username and password

* Set ID for change username notification

* Disable submit button if username is invalid

* Improve username confirmation handling

* refactor(settings): address remaining code comments on auth form

* Revert "refactor(settings): address remaining code comments on auth form"

This reverts commit 9b6609ad64.

* Social user username (#10620)

* Refactored private functions to library

* Refactored social login code

* Added username to social registration

* Changed id library

* Added new local auth check

* Fixed export error. Fixed password check error

* fix(settings): password not available on client

* refactor(settings): more sensible placement of methods

* chore(migration): script to hand out procgen usernames

* fix(migration): don't give EVERYONE new names you doofus

* fix(migration): limit data retrieved, be extra careful about updates

* fix(migration): use missing field, not migration tag, for query

* fix(migration): unused var

* fix(usernames): only generate 20 characters

* fix(migration): set lowerCaseUsername
2018-10-02 16:17:06 -05:00

221 lines
6.5 KiB
Vue

<template lang="pug">
.form
.form-group.row.text-center
.col-12.col-md-6
.btn.btn-secondary.social-button(@click='socialAuth("facebook")')
.svg-icon.social-icon(v-html="icons.facebookIcon")
span {{registering ? $t('signUpWithSocial', {social: 'Facebook'}) : $t('loginWithSocial', {social: 'Facebook'})}}
.col-12.col-md-6
.btn.btn-secondary.social-button(@click='socialAuth("google")')
.svg-icon.social-icon(v-html="icons.googleIcon")
span {{registering ? $t('signUpWithSocial', {social: 'Google'}) : $t('loginWithSocial', {social: 'Google'})}}
.form-group(v-if='registering')
label(for='usernameInput', v-once) {{$t('username')}}
input#usernameInput.form-control(type='text', :placeholder='$t("usernamePlaceholder")', v-model='username', :class='{"input-valid": usernameValid, "input-invalid": usernameInvalid}')
.form-group(v-if='!registering')
label(for='usernameInput', v-once) {{$t('emailOrUsername')}}
input#usernameInput.form-control(type='text', :placeholder='$t("emailOrUsername")', v-model='username')
.form-group(v-if='registering')
label(for='emailInput', v-once) {{$t('email')}}
input#emailInput.form-control(type='email', :placeholder='$t("emailPlaceholder")', v-model='email', :class='{"input-invalid": emailInvalid, "input-valid": emailValid}')
.form-group
label(for='passwordInput', v-once) {{$t('password')}}
a.float-right.forgot-password(v-once, v-if='!registering', @click='forgotPassword = true') {{$t('forgotPassword')}}
input#passwordInput.form-control(type='password', :placeholder='$t(registering ? "passwordPlaceholder" : "password")', v-model='password')
.form-group(v-if='registering')
label(for='confirmPasswordInput', v-once) {{$t('confirmPassword')}}
input#confirmPasswordInput.form-control(type='password', :placeholder='$t("confirmPasswordPlaceholder")', v-model='passwordConfirm', :class='{"input-invalid": passwordConfirmInvalid, "input-valid": passwordConfirmValid}')
small.form-text(v-once, v-html="$t('termsAndAgreement')")
.text-center
.btn.btn-info(@click='register()', v-if='registering', v-once) {{$t('joinHabitica')}}
.btn.btn-info(@click='login()', v-if='!registering', v-once) {{$t('login')}}
</template>
<style lang="scss" scoped>
@import '~client/assets/scss/colors.scss';
.form {
margin: 0 auto;
width: 100%;
padding-top: 2em;
padding-bottom: 4em;
position: relative;
z-index: 1;
.form-group {
text-align: left;
font-weight: bold;
}
.social-button {
width: 100%;
height: 100%;
white-space: inherit;
text-align: center;
.text {
display: inline-block;
min-height: 0px;
}
}
.social-icon {
margin-right: 1em;
width: 18px;
height: 18px;
display: inline-block;
vertical-align: top;
margin-top: .2em;
}
small.form-text {
text-align: center;
}
.input-valid {
color: #fff;
}
}
</style>
<script>
import hello from 'hellojs';
import { setUpAxios } from 'client/libs/auth';
import debounce from 'lodash/debounce';
import facebookSquareIcon from 'assets/svg/facebook-square.svg';
import googleIcon from 'assets/svg/google.svg';
export default {
name: 'AuthForm',
data () {
let data = {
registering: true,
username: '',
email: '',
password: '',
passwordConfirm: '',
usernameIssues: [],
};
data.icons = Object.freeze({
facebookIcon: facebookSquareIcon,
googleIcon,
});
return data;
},
mounted () {
hello.init({
facebook: process.env.FACEBOOK_KEY, // eslint-disable-line
// windows: WINDOWS_CLIENT_ID,
google: process.env.GOOGLE_CLIENT_ID, // eslint-disable-line
});
},
computed: {
emailValid () {
if (this.email.length <= 3) return false;
return this.validateEmail(this.email);
},
emailInvalid () {
return !this.emailValid;
},
usernameValid () {
if (this.username.length <= 3) return false;
return this.usernameIssues.length === 0;
},
usernameInvalid () {
return !this.usernameValid;
},
passwordConfirmValid () {
if (this.passwordConfirm.length <= 3) return false;
return this.passwordConfirm === this.password;
},
passwordConfirmInvalid () {
return !this.passwordConfirmValid;
},
},
watch: {
username () {
this.validateUsername(this.username);
},
},
methods: {
// eslint-disable-next-line func-names
validateUsername: debounce(function (username) {
if (username.length <= 3) {
return;
}
this.$store.dispatch('auth:verifyUsername', {
username: this.username,
}).then(res => {
if (res.issues !== undefined) {
this.usernameIssues = res.issues;
} else {
this.usernameIssues = [];
}
});
}, 500),
// @TODO: Abstract hello in to action or lib
async socialAuth (network) {
try {
await hello(network).logout();
} catch (e) {} // eslint-disable-line
try {
const redirectUrl = `${window.location.protocol}//${window.location.host}`;
let auth = await hello(network).login({
scope: 'email',
redirect_uri: redirectUrl, // eslint-disable-line camelcase
});
await this.$store.dispatch('auth:socialAuth', {
auth,
});
await this.finishAuth();
} catch (err) {
console.error(err); // eslint-disable-line no-console
// logout the user
await hello(network).logout();
this.socialAuth(network); // login again
}
},
async register () {
if (!this.email) {
alert(this.$t('missingEmail'));
return;
}
if (this.password !== this.passwordConfirm) {
alert(this.$t('passwordConfirmationMatch'));
return;
}
try {
await this.$store.dispatch('auth:register', {
username: this.username,
email: this.email,
password: this.password,
passwordConfirm: this.passwordConfirm,
});
await this.finishAuth();
} catch (e) {
if (e.response.data.data && e.response.data.data.errors) {
const message = e.response.data.data.errors.map(error => `${error.message}\n`);
alert(message);
}
}
},
async finishAuth () {
setUpAxios();
await this.$store.dispatch('user:fetch', {forceLoad: true});
this.$emit('authenticate');
},
},
};
</script>