rename components, add cypress tests, update hash
This commit is contained in:
parent
236afbeb4f
commit
13685b082e
|
|
@ -0,0 +1,95 @@
|
||||||
|
describe('Change Password Page', () => {
|
||||||
|
|
||||||
|
const validNewPassword = 'Abcd1234!';
|
||||||
|
const validOldPassword = 'test';
|
||||||
|
const validationTooShort = 'Das neue Passwort muss mindestens 8 Zeichen lang sein';
|
||||||
|
const validationErrorMsg = 'Das Passwort muss Grossbuchstaben, Zahlen und Sonderzeichen beinhalten';
|
||||||
|
const validationOldWrongMsg = 'Die Eingabe ist falsch';
|
||||||
|
|
||||||
|
after(function () {
|
||||||
|
cy.exec("python ../server/manage.py reset_testuser_password rahel.cueni");
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows an empty form', () => {
|
||||||
|
cy.login('rahel.cueni', 'test');
|
||||||
|
cy.visit('/password-change');
|
||||||
|
|
||||||
|
cy.get('[data-cy=password-change-success]').should('not.exist');
|
||||||
|
cy.get('[data-cy=old-password]').should('have.value', '');
|
||||||
|
cy.get('[data-cy=new-password]').should('have.value', '');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows errors if old password is not entered', () => {
|
||||||
|
cy.login('rahel.cueni', 'test');
|
||||||
|
cy.visit('/password-change');
|
||||||
|
|
||||||
|
cy.changePassword('', validNewPassword);
|
||||||
|
cy.get('[data-cy=old-password-local-errors]').should('contain', 'Dein aktuelles Passwort fehlt')
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows errors if old password is not entered', () => {
|
||||||
|
cy.login('rahel.cueni', 'test');
|
||||||
|
cy.visit('/password-change');
|
||||||
|
|
||||||
|
cy.changePassword(validOldPassword, '');
|
||||||
|
cy.get('[data-cy=new-password-local-errors]').should('contain', 'Dein neues Passwort fehlt')
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows errors if new password is too short', () => {
|
||||||
|
cy.login('rahel.cueni', 'test');
|
||||||
|
cy.visit('/password-change');
|
||||||
|
|
||||||
|
cy.changePassword(validOldPassword, 'Abc1!');
|
||||||
|
cy.get('[data-cy=new-password-local-errors]').should('contain', validationTooShort)
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows errors if new password has no uppercase letter', () => {
|
||||||
|
cy.login('rahel.cueni', 'test');
|
||||||
|
cy.visit('/password-change');
|
||||||
|
|
||||||
|
cy.changePassword(validOldPassword, 'aabdddedddbc1!');
|
||||||
|
cy.get('[data-cy=new-password-local-errors]').should('contain', validationErrorMsg)
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows errors if new password has no lowercase letter', () => {
|
||||||
|
cy.login('rahel.cueni', 'test');
|
||||||
|
cy.visit('/password-change');
|
||||||
|
|
||||||
|
cy.changePassword(validOldPassword, 'ABCDDD334551!');
|
||||||
|
cy.get('[data-cy=new-password-local-errors]').should('contain', validationErrorMsg)
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows errors if new password has no digit', () => {
|
||||||
|
cy.login('rahel.cueni', 'test');
|
||||||
|
cy.visit('/password-change');
|
||||||
|
|
||||||
|
cy.changePassword(validOldPassword, 'AbcdEEDE!');
|
||||||
|
cy.get('[data-cy=new-password-local-errors]').should('contain', validationErrorMsg)
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows errors if new password has no special character', () => {
|
||||||
|
cy.login('rahel.cueni', 'test');
|
||||||
|
cy.visit('/password-change');
|
||||||
|
|
||||||
|
cy.changePassword(validOldPassword, 'AbcdEEDE09877');
|
||||||
|
cy.get('[data-cy=new-password-local-errors]').should('contain', validationErrorMsg)
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows errors if old password does not match', () => {
|
||||||
|
cy.login('rahel.cueni', 'test');
|
||||||
|
cy.visit('/password-change');
|
||||||
|
|
||||||
|
cy.changePassword('test12345', validNewPassword);
|
||||||
|
cy.get('[data-cy=old-password-remote-errors]').should('contain', validationOldWrongMsg)
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows success if change was successful', () => {
|
||||||
|
cy.login('rahel.cueni', 'test');
|
||||||
|
cy.visit('/password-change');
|
||||||
|
|
||||||
|
cy.changePassword('test', validNewPassword);
|
||||||
|
cy.get('[data-cy=password-change-success]').should('contain', 'Dein Password wurde erfolgreich geändert.');
|
||||||
|
cy.get('[data-cy=old-password]').should('have.value', '');
|
||||||
|
cy.get('[data-cy=new-password]').should('have.value', '');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -68,3 +68,14 @@ Cypress.Commands.add('waitFor', operationName => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Cypress.Commands.add('changePassword', (oldPassword, newPassword) => {
|
||||||
|
if (oldPassword) {
|
||||||
|
cy.get('[data-cy=old-password]').type(oldPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newPassword) {
|
||||||
|
cy.get('[data-cy=new-password]').type(newPassword);
|
||||||
|
}
|
||||||
|
cy.get('[data-cy=change-password-button]').click();
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="pw-reset">
|
<div class="pw-change">
|
||||||
<form class="pw-reset__form reset-form" novalidate @submit.prevent="validateBeforeSubmit">
|
<form class="pw-change__form change-form" novalidate @submit.prevent="validateBeforeSubmit">
|
||||||
<div class="reset-form__field sbform-input">
|
<div class="change-form__field sbform-input">
|
||||||
<label for="old-pw" class="sbform-input__label">Aktuells Passwort</label>
|
<label for="old-pw" class="sbform-input__label">Aktuells Passwort</label>
|
||||||
<input id="old-pw"
|
<input id="old-pw"
|
||||||
name="oldPassword"
|
name="oldPassword"
|
||||||
|
|
@ -9,11 +9,13 @@
|
||||||
v-model="oldPassword"
|
v-model="oldPassword"
|
||||||
v-validate="'required'"
|
v-validate="'required'"
|
||||||
:class="{ 'sbform-input__input--error': errors.has('oldPassword') }"
|
:class="{ 'sbform-input__input--error': errors.has('oldPassword') }"
|
||||||
class="reset-form__old skillbox-input sbform-input__input">
|
class="change-form__old skillbox-input sbform-input__input"
|
||||||
<small v-if="errors.has('oldPassword') && submitted" class="sbform-input__error">{{ errors.first('oldPassword') }}</small>
|
autocomplete="off"
|
||||||
<small v-for="error in oldPasswordErrors" :key="error" class=" sbform-input__error">{{ error }}</small>
|
data-cy="old-password">
|
||||||
|
<small v-if="errors.has('oldPassword') && submitted" class="sbform-input__error" data-cy="old-password-local-errors">{{ errors.first('oldPassword') }}</small>
|
||||||
|
<small v-for="error in oldPasswordErrors" :key="error" class=" sbform-input__error" data-cy="old-password-remote-errors">{{ error }}</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="reset-form__field sbform-input">
|
<div class="change-form__field sbform-input">
|
||||||
<label for="new-pw" class="sbform-input__label">Neues Passwort</label>
|
<label for="new-pw" class="sbform-input__label">Neues Passwort</label>
|
||||||
<input id="new-pw"
|
<input id="new-pw"
|
||||||
name="newPassword"
|
name="newPassword"
|
||||||
|
|
@ -21,11 +23,13 @@
|
||||||
v-model="newPassword"
|
v-model="newPassword"
|
||||||
v-validate="'required|min:8|strongPassword'"
|
v-validate="'required|min:8|strongPassword'"
|
||||||
:class="{ 'sbform-input__input--error': errors.has('newPassword') }"
|
:class="{ 'sbform-input__input--error': errors.has('newPassword') }"
|
||||||
class="reset-form__new skillbox-input sbform-input__input">
|
class="change-form__new skillbox-input sbform-input__input"
|
||||||
<small v-if="errors.has('newPassword') && submitted" class=" sbform-input__error">{{ errors.first('newPassword') }}</small>
|
autocomplete="off"
|
||||||
<small v-for="error in newPasswordErrors" :key="error" class=" sbform-input__error">{{ error }}</small>
|
data-cy="new-password">
|
||||||
|
<small v-if="errors.has('newPassword') && submitted" class=" sbform-input__error" data-cy="new-password-local-errors">{{ errors.first('newPassword') }}</small>
|
||||||
|
<small v-for="error in newPasswordErrors" :key="error" class=" sbform-input__error" data-cy="new-password-remote-errors">{{ error }}</small>
|
||||||
</div>
|
</div>
|
||||||
<button class="button button--primary reset-form__submit">Zurücksetzen</button>
|
<button class="button button--primary change-form__submit" data-cy="change-password-button">Zurücksetzen</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -49,8 +53,19 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
resetForm () {
|
||||||
|
this.oldPassword = '';
|
||||||
|
this.newPassword = '';
|
||||||
|
this.submitted = false;
|
||||||
|
this.$validator.reset();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
mounted() {
|
||||||
|
this.$root.$on('reset-password-form', () => {
|
||||||
|
this.resetForm();
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -58,7 +73,7 @@
|
||||||
@import "@/styles/_variables.scss";
|
@import "@/styles/_variables.scss";
|
||||||
@import "@/styles/_buttons.scss";
|
@import "@/styles/_buttons.scss";
|
||||||
|
|
||||||
.reset-form {
|
.change-form {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
|
|
||||||
@media screen and (max-width: 1024px) {
|
@media screen and (max-width: 1024px) {
|
||||||
|
|
@ -82,7 +82,7 @@ Validator.extend('min', min);
|
||||||
const dict = {
|
const dict = {
|
||||||
custom: {
|
custom: {
|
||||||
oldPassword: {
|
oldPassword: {
|
||||||
required: 'Dein jetztiges Passwort fehlt'
|
required: 'Dein aktuelles Passwort fehlt'
|
||||||
},
|
},
|
||||||
newPassword: {
|
newPassword: {
|
||||||
required: 'Dein neues Passwort fehlt',
|
required: 'Dein neues Passwort fehlt',
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="password-reset">
|
<div class="password-reset">
|
||||||
<h1 class="password-reset__header">Passwort Zurücksetzen</h1>
|
<h1 class="password-reset__header">Passwort ändern</h1>
|
||||||
<password-reset
|
<div v-if="showSuccess" class="success-message">
|
||||||
|
<p class="success-message__msg" data-cy="password-change-success">Dein Password wurde erfolgreich geändert.</p>
|
||||||
|
</div>
|
||||||
|
<password-change
|
||||||
@passwordSubmited="resetPassword"
|
@passwordSubmited="resetPassword"
|
||||||
:oldPasswordErrors="oldPasswordErrors"
|
:oldPasswordErrors="oldPasswordErrors"
|
||||||
:newPasswordErrors="newPasswordErrors" />
|
:newPasswordErrors="newPasswordErrors" />
|
||||||
|
|
@ -11,17 +14,18 @@
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import UPDATE_PASSWORD_MUTATION from '@/graphql/gql/mutations/updatePassword.gql';
|
import UPDATE_PASSWORD_MUTATION from '@/graphql/gql/mutations/updatePassword.gql';
|
||||||
import PasswordReset from '@/components/PasswordReset'
|
import PasswordChange from '@/components/PasswordChange'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
PasswordReset
|
PasswordChange
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
oldPasswordErrors: [],
|
oldPasswordErrors: [],
|
||||||
newPasswordErrors: []
|
newPasswordErrors: [],
|
||||||
|
showSuccess: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -37,6 +41,8 @@
|
||||||
if (data.updatePassword.success) {
|
if (data.updatePassword.success) {
|
||||||
this.oldPasswordErrors = [];
|
this.oldPasswordErrors = [];
|
||||||
this.newPasswordErrors = [];
|
this.newPasswordErrors = [];
|
||||||
|
this.showSuccess = true;
|
||||||
|
this.$root.$emit('reset-password-form')
|
||||||
} else {
|
} else {
|
||||||
// currently we just have one error per field
|
// currently we just have one error per field
|
||||||
const error = data.updatePassword.errors[0]
|
const error = data.updatePassword.errors[0]
|
||||||
|
|
@ -82,4 +88,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.success-message {
|
||||||
|
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
&__msg {
|
||||||
|
color: $color-accent-4-dark;
|
||||||
|
font-family: $sans-serif-font-family;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -19,7 +19,7 @@ import submission from '@/pages/studentSubmission'
|
||||||
import portfolio from '@/pages/portfolio'
|
import portfolio from '@/pages/portfolio'
|
||||||
import project from '@/pages/project'
|
import project from '@/pages/project'
|
||||||
import profilePage from '@/pages/profile'
|
import profilePage from '@/pages/profile'
|
||||||
import passwordReset from '@/pages/passwordReset'
|
import passwordChange from '@/pages/passwordChange'
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{path: '/', component: start, meta: {layout: 'blank'}},
|
{path: '/', component: start, meta: {layout: 'blank'}},
|
||||||
|
|
@ -65,7 +65,7 @@ const routes = [
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{path: '/me', name: 'profile', component: profilePage},
|
{path: '/me', name: 'profile', component: profilePage},
|
||||||
{path: '/password-reset', name: 'pw-reset', component: passwordReset},
|
{path: '/password-change', name: 'pw-change', component: passwordChange},
|
||||||
{path: '*', component: p404}
|
{path: '*', component: p404}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# ITerativ GmbH
|
||||||
|
# http://www.iterativ.ch/
|
||||||
|
#
|
||||||
|
# Copyright (c) 2019 ITerativ GmbH. All rights reserved.
|
||||||
|
#
|
||||||
|
# Created on 2019-04-08
|
||||||
|
# @author: chrigu <christian.cueni@iterativ.ch>
|
||||||
|
from django.conf import settings
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.core.management import BaseCommand
|
||||||
|
|
||||||
|
from books.models import Module
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
# Positional arguments
|
||||||
|
parser.add_argument('username', nargs='+', type=str)
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
self.stdout.write("Reset Testuser Password")
|
||||||
|
|
||||||
|
email = "{}@skillbox.example".format(options['username'][0])
|
||||||
|
|
||||||
|
try:
|
||||||
|
user = get_user_model().objects.get(email=email)
|
||||||
|
user.set_password('test')
|
||||||
|
user.save()
|
||||||
|
self.stdout.write("Password reset successful")
|
||||||
|
except get_user_model().DoesNotExist:
|
||||||
|
self.stdout.write("No user found!")
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import graphene
|
import graphene
|
||||||
|
from django.contrib.auth import update_session_auth_hash
|
||||||
from graphene import relay
|
from graphene import relay
|
||||||
from users.inputs import PasswordUpdateInput
|
from users.inputs import PasswordUpdateInput
|
||||||
from users.serializers import PasswordSerialzer
|
from users.serializers import PasswordSerialzer
|
||||||
|
|
@ -30,6 +31,7 @@ class UpdatePassword(relay.ClientIDMutation):
|
||||||
if serializer.is_valid():
|
if serializer.is_valid():
|
||||||
user.set_password(password_data['new_password'])
|
user.set_password(password_data['new_password'])
|
||||||
user.save()
|
user.save()
|
||||||
|
update_session_auth_hash(info.context, user)
|
||||||
return cls(success=True)
|
return cls(success=True)
|
||||||
|
|
||||||
errors = []
|
errors = []
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,6 @@ def create_users(data=None):
|
||||||
name='second_class'
|
name='second_class'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
for school_class in data:
|
for school_class in data:
|
||||||
first, last = school_class.get('teacher')
|
first, last = school_class.get('teacher')
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue