Skip to content

Commit

Permalink
Merge branch 'feature/new-password-requirements' into staging
Browse files Browse the repository at this point in the history
  • Loading branch information
tsubik committed Oct 1, 2024
2 parents b34c2d9 + 8463a76 commit d5d6eb6
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
uses: actions/checkout@v4
with:
repository: wri/fti_api
ref: master
ref: feature/new-password-requirements
path: otp_api

- name: Save OTP API Commit SHA
Expand Down
40 changes: 39 additions & 1 deletion components/form/Validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,44 @@ class Validator {
message: intl.formatMessage({ id: 'The field is required' })
},

minLength: {
validate(value, condition) {
return value.length >= condition;
},
message: (condition) => intl.formatMessage({ id: 'validation.minLength', defaultMessage: 'The field should have at least {min} characters' }, { min: condition })
},

maxLength: {
validate(value, condition) {
return value.length <= condition;
},
message: (condition) => intl.formatMessage({ id: 'validation.maxLength', defaultMessage: 'The field should have at most {max} characters' }, { max: condition })
},

haveLowercaseLetter: {
validate(value) {
const regex = /(?=.*[a-z]).+/;
return regex.test(value || '');
},
message: intl.formatMessage({ id: 'validation.haveLowercaseLetter', defaultMessage: 'The field should have at least one lowercase letter' })
},

haveUppercaseLetter: {
validate(value) {
const regex = /(?=.*[A-Z]).+/;
return regex.test(value || '');
},
message: intl.formatMessage({ id: 'validation.haveUppercaseLetter', defaultMessage: 'The field should have at least one capital (uppercase) letter' })
},

haveDigit: {
validate(value) {
const regex = /(?=.*\d).+/;
return regex.test(value || '');
},
message: intl.formatMessage({ id: 'validation.haveDigit', defaultMessage: 'The field should have at least one digit' })
},

email: {
validate(value) {
const regex = /\S+@\S+\.\S+/;
Expand Down Expand Up @@ -59,7 +97,7 @@ class Validator {
if (typeof validation === 'object') {
const validObj = this.validations[validation.type];
valid = validObj.validate(value, validation.condition);
message = validation.message || validObj.message || '';
message = validation.message || ((validObj.message && typeof validObj.message === 'function') ? validObj.message(validation.condition) : validObj.message) || '';
}

return {
Expand Down
13 changes: 13 additions & 0 deletions components/users/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,19 @@ const UserEditForm = (props) => {
</h2>

<Field
validations={[
'haveLowercaseLetter',
'haveUppercaseLetter',
'haveDigit',
{
type: 'minLength',
condition: 10
},
{
type: 'maxLength',
condition: 128
}
]}
className="-fluid"
properties={{
name: 'password',
Expand Down
15 changes: 14 additions & 1 deletion components/users/new.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,20 @@ const UserNewForm = (props) => {
</Field>

<Field
validations={['required']}
validations={[
'required',
'haveLowercaseLetter',
'haveUppercaseLetter',
'haveDigit',
{
type: 'minLength',
condition: 10
},
{
type: 'maxLength',
condition: 128
}
]}
className="-fluid"
properties={{
name: 'password',
Expand Down
19 changes: 17 additions & 2 deletions components/users/reset-password.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,35 @@ const ResetPasswordForm = ({ token }) => {
<Form>
<fieldset className="c-field-container">
<Field
validations={[
'required',
'haveLowercaseLetter',
'haveUppercaseLetter',
'haveDigit',
{
type: 'minLength',
condition: 10
},
{
type: 'maxLength',
condition: 128
}
]}
className="-fluid"
properties={{
name: 'password',
autoComplete: 'new-password',
label: intl.formatMessage({ id: 'New Password' }),
type: 'password',
required: false
required: true
}}
>
{Input}
</Field>

<Field
validations={[
'required',
{
type: 'isEqual',
condition: form.password,
Expand All @@ -69,7 +84,7 @@ const ResetPasswordForm = ({ token }) => {
autoComplete: 'new-password',
label: intl.formatMessage({ id: 'Confirm New Password' }),
type: 'password',
required: false
required: true
}}
>
{Input}
Expand Down
2 changes: 1 addition & 1 deletion e2e/cypress/e2e/operator.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('Operator', function () {

context('when logged in as Operator', function () {
beforeEach(function () {
cy.login('[email protected]', 'password');
cy.login('[email protected]', 'Supersecret1');
});

describe('updating operator profile', function () {
Expand Down
4 changes: 2 additions & 2 deletions e2e/cypress/e2e/password-reset.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ describe('Password Reset', () => {
describe('errors', () => {
it('shows error with invalid token', function () {
cy.visit('/reset-password?reset_password_token=invalid');
cy.get('#input-password').type('newpassword');
cy.get('#input-passwordConfirmation').type('newpassword');
cy.get('#input-password').type('NewPassword1');
cy.get('#input-passwordConfirmation').type('NewPassword1');
cy.get('button').contains('Change Password').click();
cy.get('.rrt-text').should('have.text', 'reset_password_token is invalid');
});
Expand Down
24 changes: 15 additions & 9 deletions e2e/cypress/e2e/user.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ describe('User', () => {
cy.get('#input-password').type('wrongpassword');
cy.get('button').contains('Log in').click();
cy.get('.rrt-text').should('have.text', 'Wrong email or password');
cy.get('#input-password').clear().type('password');
cy.get('#input-password').clear().type('Supersecret1');
cy.get('button').contains('Log in').click();
cy.contains('a', 'My account');
});
})

context('Public user', () => {
it('can log in and out', function () {
cy.login('[email protected]', 'password');
cy.login('[email protected]', 'Supersecret1');
cy.get('a').contains('My account').click();
cy.get('a').contains('My profile').click();
cy.get('#input-firstName').should('have.value', 'Operator');
Expand All @@ -44,11 +44,17 @@ describe('User', () => {
cy.get('#input-first_name').type('Test');
cy.get('#input-last_name').type('Operator');
cy.get('#input-email').type('[email protected]');
cy.get('#input-password').type('supersecret');
cy.get('#input-password_confirmation').type('supersecret');
cy.get('#input-password').type('password');
cy.get('#input-password_confirmation').type('password2');
cy.get('button').contains('Sign up').click();
cy.get('.error').should('have.text', 'The field is required');
cy.contains('.error', 'The field is required');
cy.contains('.error', 'The field should have at least one capital (uppercase) letter');
cy.contains('.error', 'The field should have at least one digit');
cy.contains('.error', 'The field should have at least 10 characters');
cy.contains('.error', 'The field should be equal to password');
cy.get('.rrt-text').should('have.text', 'Fill all the required fields');
cy.get('#input-password').clear().type('Superpassword1');
cy.get('#input-password_confirmation').clear().type('Superpassword1');
cy.get('label[for=checkbox-agree-undefined]').click();
cy.get('button').contains('Sign up').click();
cy.get('.c-info-box').contains('you will receive an email to [email protected] once your account is approved');
Expand Down Expand Up @@ -78,7 +84,7 @@ describe('User', () => {

context('Logged in User', () => {
beforeEach(() => {
cy.login('[email protected]', 'password');
cy.login('[email protected]', 'Supersecret1');
});

it('can update user profile', function () {
Expand All @@ -90,9 +96,9 @@ describe('User', () => {
cy.get('#input-lastName').clear();
cy.get('#input-lastName').type('Operator 2');
cy.selectOption('[name=locale]', 'Po', 'Português');
cy.get('#input-password').type('supersecret');
cy.get('#input-passwordConfirmation').type('supersecret');
cy.get('#input-currentPassword').type('password');
cy.get('#input-password').type('GreatPassword1');
cy.get('#input-passwordConfirmation').type('GreatPassword1');
cy.get('#input-currentPassword').type('Supersecret1');

cy.get('button').contains('Update').click();
cy.get('.rrt-text').should('have.text', 'Profile saved correctly');
Expand Down
7 changes: 6 additions & 1 deletion lang/zu.json
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,11 @@
"The field should be a valid url: http://example.com": "The field should be a valid url: http://example.com",
"The field should be a valid email address": "The field should be a valid email address",
"The field should be equal to password": "The field should be equal to password",
"validation.minLength": "The field should have at least {min} characters",
"validation.maxLength": "The field should have at most {max} characters",
"validation.haveLowercaseLetter": "The field should have at least one lowercase letter",
"validation.haveUppercaseLetter": "The field should have at least one capital (uppercase) letter",
"validation.haveDigit": "The field should have at least one digit",
"First Name": "First Name",
"Last Name": "Last Name",
"Organization": "Organization",
Expand Down Expand Up @@ -471,4 +476,4 @@
"newsletter.want_to_receive": "Want to receive the latest updates from the Open Timber Portal?",
"newsletter.subscribe_to": "Subscribe to our newsletter",
"newsletter.showing_results": "Showing {count} previous newsletters"
}
}

0 comments on commit d5d6eb6

Please sign in to comment.