Implement password change in basic user settings

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel 2019-09-24 18:47:35 +02:00
parent 4aaabced2c
commit f551a9047d
5 changed files with 135 additions and 5 deletions

View File

@ -25,6 +25,14 @@ mutation ValidateUser($token: String!) {
}
`;
export const CHANGE_PASSWORD = gql`
mutation ChangePassword($oldPassword: String!, $newPassword: String!) {
changePassword(oldPassword: $oldPassword, newPassword: $newPassword) {
id
}
}
`;
export const CURRENT_USER_CLIENT = gql`
query {
currentUser @client {

View File

@ -7,6 +7,7 @@ import SendPasswordReset from '@/views/User/SendPasswordReset.vue';
import PasswordReset from '@/views/User/PasswordReset.vue';
import { beforeRegisterGuard } from '@/router/guards/register-guard';
import { RouteConfig } from 'vue-router';
import PasswordChange from '@/views/User/PasswordChange.vue';
export enum UserRouteName {
REGISTER = 'Register',
@ -16,6 +17,7 @@ export enum UserRouteName {
PASSWORD_RESET = 'PasswordReset',
VALIDATE = 'Validate',
LOGIN = 'Login',
PASSWORD_CHANGE = 'PasswordChange',
}
export const userRoutes: RouteConfig[] = [
@ -70,4 +72,10 @@ export const userRoutes: RouteConfig[] = [
props: true,
meta: { requiredAuth: false },
},
{
path: '/my-account/password',
name: UserRouteName.PASSWORD_CHANGE,
component: PasswordChange,
meta: { requiredAuth: true },
},
];

View File

@ -1,5 +1,10 @@
<template>
<section class="container">
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li class="is-active"><router-link :to="{ name: MyAccountRouteName.UPDATE_IDENTITY }" aria-current="page">{{ $t('My account') }}</router-link></li>
</ul>
</nav>
<div v-if="currentActor">
<div class="header">
<figure v-if="currentActor.banner" class="image is-3by1">
@ -10,6 +15,9 @@
<div class="columns">
<div class="identities column is-4">
<identities v-bind:currentIdentityName="currentIdentityName"></identities>
<div class="buttons">
<b-button tag="router-link" type="is-secondary" :to="{ name: UserRouteName.PASSWORD_CHANGE }">{{ $t('Change password') }}</b-button>
</div>
</div>
<div class="column is-8">
<router-view></router-view>
@ -27,6 +35,10 @@
.identities {
padding-right: 45px;
margin-right: 45px;
.buttons {
margin-top: 1.2rem;
}
}
</style>
@ -36,6 +48,8 @@ import { Component, Vue, Watch } from 'vue-property-decorator';
import EventCard from '@/components/Event/EventCard.vue';
import { IPerson } from '@/types/actor';
import Identities from '@/components/Account/Identities.vue';
import { UserRouteName } from '@/router/user';
import { MyAccountRouteName } from '@/router/actor';
@Component({
components: {
@ -52,6 +66,9 @@ export default class MyAccount extends Vue {
currentActor!: IPerson;
currentIdentityName: string | null = null;
UserRouteName = UserRouteName;
MyAccountRouteName = MyAccountRouteName;
@Watch('$route.params.identityName', { immediate: true })
async onIdentityParamChanged (val: string) {
await this.redirectIfNoIdentitySelected(val);

View File

@ -0,0 +1,94 @@
<template>
<section class="section">
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li><router-link :to="{ name: MyAccountRouteName.UPDATE_IDENTITY }">{{ $t('My account') }}</router-link></li>
<li class="is-active"><router-link :to="{ name: UserRouteName.PASSWORD_CHANGE }" aria-current="page">{{ $t('Password change') }}</router-link></li>
</ul>
</nav>
<h1 class="title">{{ $t('Password') }}</h1>
<b-notification
type="is-danger"
has-icon
aria-close-label="Close notification"
role="alert"
:key="error"
v-for="error in errors"
>
{{ error }}
</b-notification>
<form @submit="resetAction" class="form">
<b-field :label="$t('Old password')">
<b-input
aria-required="true"
required
type="password"
password-reveal
minlength="6"
v-model="oldPassword"
/>
</b-field>
<b-field :label="$t('New password')">
<b-input
aria-required="true"
required
type="password"
password-reveal
minlength="6"
v-model="newPassword"
/>
</b-field>
<button class="button is-primary">
{{ $t('Change my password') }}
</button>
</form>
</section>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import { CHANGE_PASSWORD } from '@/graphql/user';
import { UserRouteName } from '@/router/user';
import { MyAccountRouteName } from '@/router/actor';
@Component
export default class PasswordChange extends Vue {
oldPassword: string = '';
newPassword: string = '';
errors: string[] = [];
MyAccountRouteName = MyAccountRouteName;
UserRouteName = UserRouteName;
async resetAction(e) {
e.preventDefault();
this.errors = [];
try {
await this.$apollo.mutate({
mutation: CHANGE_PASSWORD,
variables: {
oldPassword: this.oldPassword,
newPassword: this.newPassword,
},
});
this.$notifier.success(this.$t('The password was successfully changed') as string);
} catch (err) {
this.handleError(err);
}
}
private handleError(err: any) {
console.error(err);
if (err.graphQLErrors !== undefined) {
err.graphQLErrors.forEach(({ message }) => {
this.errors.push(message);
});
}
}
}
</script>
<style lang="scss">
</style>

View File

@ -1,5 +1,5 @@
# source: http://localhost:4000/api
# timestamp: Fri Sep 20 2019 16:55:10 GMT+0200 (GMT+02:00)
# timestamp: Tue Sep 24 2019 18:20:05 GMT+0200 (GMT+02:00)
schema {
query: RootQueryType
@ -184,7 +184,7 @@ enum CommentVisibility {
"""Visible only to people members of the group or followers of the person"""
PRIVATE
"""Publically listed and federated. Can be shared."""
"""Publicly listed and federated. Can be shared."""
PUBLIC
"""Visible only to people with the link - or invited"""
@ -885,6 +885,9 @@ type RootMutationType {
"""Change default actor for user"""
changeDefaultActor(preferredUsername: String!): User
"""Change an user password"""
changePassword(newPassword: String!, oldPassword: String!): User
"""Create a comment"""
createComment(actorUsername: String!, text: String!): Comment
@ -911,7 +914,7 @@ type RootMutationType {
"""The list of tags associated to the event"""
tags: [String] = [""]
title: String!
visibility: EventVisibility = PRIVATE
visibility: EventVisibility = PUBLIC
): Event
"""Create a Feed Token"""
@ -1044,7 +1047,7 @@ type RootMutationType {
description: String
endsOn: DateTime
eventId: ID!
joinOptions: EventJoinOptions
joinOptions: EventJoinOptions = FREE
onlineAddress: String
options: EventOptionsInput
phoneAddress: String
@ -1059,7 +1062,7 @@ type RootMutationType {
"""The list of tags associated to the event"""
tags: [String]
title: String
visibility: EventVisibility
visibility: EventVisibility = PUBLIC
): Event
"""Update an identity"""