summaryrefslogtreecommitdiffstats
path: root/webapp/src/components/AccountModule.vue
diff options
context:
space:
mode:
authorJannik Schönartz2019-02-23 06:37:14 +0100
committerJannik Schönartz2019-02-23 06:37:14 +0100
commitd2e1a80e2c7a4d807cb30899c0f2f20127396687 (patch)
tree1d648a3302acc9815404b2ed375b90f0dc518841 /webapp/src/components/AccountModule.vue
parent[webapp/router] Fix forwarding bug while loggedout calling / (diff)
downloadbas-d2e1a80e2c7a4d807cb30899c0f2f20127396687.tar.gz
bas-d2e1a80e2c7a4d807cb30899c0f2f20127396687.tar.xz
bas-d2e1a80e2c7a4d807cb30899c0f2f20127396687.zip
[Account] Add password change functionality
[server] Remove hased password from userinfo api Implement change password function [webapp] Fix z-index for the fixed tab bar (udo) Implement userinfo and change password in the account module
Diffstat (limited to 'webapp/src/components/AccountModule.vue')
-rw-r--r--webapp/src/components/AccountModule.vue244
1 files changed, 237 insertions, 7 deletions
diff --git a/webapp/src/components/AccountModule.vue b/webapp/src/components/AccountModule.vue
index e9a4cce..3ac6af7 100644
--- a/webapp/src/components/AccountModule.vue
+++ b/webapp/src/components/AccountModule.vue
@@ -1,39 +1,269 @@
<i18n>
{
"en": {
+ "accountInfo": "Info",
+ "passwordConfirm": "Retype password",
+ "passwordChanged": "Password successfully changed.",
+ "passwordCurrent": "Current password",
+ "passwordEmptyError": "Password can not be empty.",
+ "passwordInvalidError": "Password incorrect.",
+ "passwordLengthError": "Minimum 8 characters required.",
+ "passwordMatchError": "Passwords do not match.",
+ "passwordNew": "New password",
+ "passwordNotDifferentError": "New password must be different than the current password.",
+ "passwordRequirement1": ">= 8 characters",
+ "passwordRequirement2": "0+ [0-9]",
+ "passwordRequirement3": "0+ [a-z]",
+ "passwordRequirement4": "0+ [A-Z]",
+ "passwordRequirement5": "0+ [!\"§$%&/()=?+#*.:,;]",
+ "passwordRequirements": "Password requirements"
},
"de": {
+ "accountInfo": "Info",
+ "passwordChanged": "Passwort wurde erfolgreich geändert.",
+ "passwordConfirm": "Passwort wiederholen",
+ "passwordCurrent": "Aktuelles Passwort",
+ "passwordEmptyError": "Passwort kann nicht leer sein.",
+ "passwordInvalidError": "Falsches Passwort.",
+ "passwordLengthError": "Es sind mindestens 8 Zeichen erforderlich.",
+ "passwordMatchError": "Passwörter stimmen nicht überein.",
+ "passwordNew": "Neues Password",
+ "passwordNotDifferentError": "Das neue Passwort muss sich vom alten unterscheiden.",
+ "passwordRequirement1": ">= 8 Zeichen",
+ "passwordRequirement2": "0+ [0-9]",
+ "passwordRequirement3": "0+ [a-z]",
+ "passwordRequirement4": "0+ [A-Z]",
+ "passwordRequirement5": "0+ [!\"§$%&/()=?+#*'-_.:,;]",
+ "passwordRequirements": "Passwort anforderungen"
}
}
</i18n>
<template>
- <div class="account-page">
- <div style="display: flex; justify-content: center; margin-top: 40px">
- <v-btn color="primary" @click="newAlert">New Alert</v-btn>
- </div>
- </div>
+ <v-container fill-height>
+ <v-layout>
+ <v-flex class="tabs-wrapper" xl10 offset-xl1 lg12>
+ <v-card>
+ <v-tabs :dark="tabsDark" :color="tabsColor" :slider-color="tabsSliderColor"
+ v-model="tab"
+ centered
+ >
+ <v-tab>
+ {{ $t('accountInfo') }}
+ </v-tab>
+ </v-tabs>
+ </v-card>
+ <v-tabs-items v-model="tab">
+ <v-tab-item>
+
+ <v-subheader>{{ $t('accountInfo') }}</v-subheader>
+ <v-card>
+ <v-card-text>
+ <v-layout wrap>
+ <v-flex lg4 md6 xs12 order-lg1 order-xs2>
+ <v-layout column>
+ <div class="info-input">
+ <div class="body-2 info-heading"><v-icon>account_circle</v-icon><span>{{ $t('username') }}</span></div>
+ <div class="info-text">{{ user.username }}</div>
+ </div>
+ </v-layout>
+ </v-flex>
+ <v-flex lg4 md6 xs12 order-lg2 order-xs3>
+ <v-layout column>
+ <div class="info-input">
+ <div class="body-2 info-heading"><v-icon>label</v-icon><span>{{ $t('name') }}</span></div>
+ <div class="info-text">{{ user.name }}</div>
+ </div>
+ </v-layout>
+ </v-flex>
+ <v-flex lg4 md6 xs12 order-lg2 order-xs3>
+ <v-layout column>
+ <div class="info-input">
+ <div class="body-2 info-heading"><v-icon>email</v-icon><span>{{ $t('email') }}</span></div>
+ <div class="info-text">{{ user.email }}</div>
+ </div>
+ </v-layout>
+ </v-flex>
+ </v-layout>
+ </v-card-text>
+ </v-card>
+
+ <v-subheader>{{ $t('security') }}</v-subheader>
+ <v-card>
+ <v-card-text>
+ <v-layout wrap>
+
+ <v-flex lg4 md6 xs12 order-lg1 order-xs2>
+ <v-layout column>
+ <div class="info-input">
+ <div class="body-2 info-heading"><v-icon>ballot</v-icon><span>{{ $t('passwordRequirements') }}</span></div>
+ <div class="info-text">{{ $t('passwordRequirement1') }}</div>
+ <div class="info-text">{{ $t('passwordRequirement2') }}</div>
+ <div class="info-text">{{ $t('passwordRequirement3') }}</div>
+ <div class="info-text">{{ $t('passwordRequirement4') }}</div>
+ <div class="info-text">{{ $t('passwordRequirement5') }}</div>
+ </div>
+ </v-layout>
+ </v-flex>
+
+ <v-flex lg4 md6 xs12 order-lg1 order-xs2>
+ <v-layout column>
+ <div class="info-input">
+ <div class="body-2 info-heading"><v-icon>lock</v-icon><span>{{ $t('password') }}</span></div>
+ <div v-if="!editPasswordMode" class="info-text">********</div>
+ <div v-else>
+ <v-form class="password-form" ref="passwordForm" v-model="valid" lazy-validation>
+ <v-text-field
+ type="password"
+ v-model="passwordCurrent"
+ :label="$t('passwordCurrent')"
+ :rules="currentPasswordRules"
+ @input="clearCurrentPasswordErrors"
+ ></v-text-field>
+ <v-text-field
+ validate-on-blur
+ type="password"
+ v-model="passwordNew"
+ :label="$t('passwordNew')"
+ :rules="passwordRules"
+ ></v-text-field>
+ <v-text-field
+ validate-on-blur
+ type="password"
+ v-model="passwordConfirm"
+ :label="$t('passwordConfirm')"
+ :rules="confirmPasswordRules"
+ ></v-text-field>
+ </v-form>
+ </div>
+ </div>
+ </v-layout>
+ </v-flex>
+
+ <v-flex lg4 xs12 order-lg3 order-xs1 class="text-xs-right">
+ <div class="info-input">
+ <v-btn v-if="!editPasswordMode" color="primary" flat @click="editPassword" class="info-buttons">
+ <v-icon left>create</v-icon>{{ $t('edit') }}
+ </v-btn>
+ <div v-else>
+ <v-btn color="primary" flat @click="cancelEditPassword" class="info-buttons">{{ $t('cancel') }}</v-btn>
+ <v-btn color="primary" @click="submitPassword" class="info-buttons">
+ <v-icon left>save</v-icon>{{ $t('save') }}
+ </v-btn>
+ </div>
+ </div>
+ </v-flex>
+
+ </v-layout>
+ </v-card-text>
+ </v-card>
+
+ <v-subheader>{{ $t('TODO REMOVE: Testing stuff') }}</v-subheader>
+ <v-card>
+ <div style="display: flex; justify-content: center;">
+ <v-btn color="primary" @click="newAlert">New Alert</v-btn>
+ </div>
+ </v-card>
+
+ </v-tab-item>
+ </v-tabs-items>
+ </v-flex>
+ </v-layout>
+ </v-container>
+
</template>
<script>
-
+import { mapGetters } from 'vuex'
export default {
name: 'AccountPage',
data () {
return {
+ tab: 0,
+ valid: true,
+ user: '',
+ passwordConfirm: '',
+ passwordCurrent: '',
+ passwordNew: '',
+ invalidPasswordError: false,
+ editPasswordMode: false,
+ currentPasswordRules: [
+ v => !!v || this.$t('passwordEmptyError'),
+ v => !this.invalidPasswordError || this.$t('passwordInvalidError')
+ ],
+ passwordRules: [
+ v => !!v || this.$t('passwordEmptyError'),
+ v => v.length >= 8 || this.$t('passwordLengthError'),
+ v => v !== this.passwordCurrent || this.$t('passwordNotDifferentError')
+ ],
+ confirmPasswordRules: [
+ v => this.passwordConfirm === this.passwordNew || this.$t('passwordMatchError')
+ ],
testId: 0
}
},
+ computed: {
+ ...mapGetters(['tabsDark', 'tabsColor', 'tabsSliderColor'])
+ },
methods: {
+ clearCurrentPasswordErrors () {
+ this.invalidPasswordError = false
+ },
+ submitPassword () {
+ if (this.$refs.passwordForm.validate()) {
+ this.$http.post('/api/users/' + this.user.id + '/password', { passwordCurrent: this.passwordCurrent, passwordNew: this.passwordNew }).then(response => {
+ this.cancelEditPassword()
+ this.$snackbar({ color: 'success', text: this.$t('passwordChanged') })
+ }).catch(error => {
+ if (error.response.data.status === 'PASSWORD_INVALID') {
+ this.invalidPasswordError = true
+ this.passwordNew = ''
+ this.passwordConfirm = ''
+ }
+ this.$refs.passwordForm.validate()
+ })
+ }
+ },
+ editPassword () {
+ this.editPasswordMode = true
+ },
+ cancelEditPassword () {
+ this.editPasswordMode = false
+ this.passwordCurrent = ''
+ this.passwordNew = ''
+ this.passwordConfirm = ''
+ },
newAlert () {
this.$alert({ type: 'success', text: 'test ' + this.testId })
this.testId++
}
+ },
+ created () {
+ this.$http('/api/users/current').then(response => {
+ this.user = response.data
+ })
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
-
+.info-buttons {
+ margin: 0;
+}
+.info-input {
+ margin: 20px;
+}
+.info-heading {
+ display: flex;
+ align-items: center;
+ margin-bottom: 10px;
+}
+.info-heading > span {
+ margin-left: 10px;
+}
+.info-text {
+ margin-left: 34px;
+ font-family: 'Roboto Mono';
+}
</style>