Skip to content

Commit

Permalink
fix(core): Normalize email address on updating Customer
Browse files Browse the repository at this point in the history
Fixes #2449
  • Loading branch information
michaelbromley committed Oct 17, 2023
1 parent 02fe6ae commit 957d0ad
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 6 deletions.
37 changes: 37 additions & 0 deletions packages/core/e2e/customer.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,22 @@ describe('Customer resolver', () => {
expect(createCustomer.message).toBe('The email address is not available.');
expect(createCustomer.errorCode).toBe(ErrorCode.EMAIL_ADDRESS_CONFLICT_ERROR);
});

it('normalizes email address on creation', async () => {
const { createCustomer } = await adminClient.query<
Codegen.CreateCustomerMutation,
Codegen.CreateCustomerMutationVariables
>(CREATE_CUSTOMER, {
input: {
emailAddress: ' JoeSmith@test.com ',
firstName: 'Joe',
lastName: 'Smith',
},
password: 'test',
});
customerErrorGuard.assertSuccess(createCustomer);
expect(createCustomer.emailAddress).toBe('joesmith@test.com');
});
});

describe('update', () => {
Expand Down Expand Up @@ -566,6 +582,27 @@ describe('Customer resolver', () => {

expect(me?.identifier).toBe('unique-email@test.com');
});

// https://github.com/vendure-ecommerce/vendure/issues/2449
it('normalizes email address on update', async () => {
const { updateCustomer } = await adminClient.query<
Codegen.UpdateCustomerMutation,
Codegen.UpdateCustomerMutationVariables
>(UPDATE_CUSTOMER, {
input: {
id: thirdCustomer.id,
emailAddress: ' Another-Address@test.com ',
},
});
customerErrorGuard.assertSuccess(updateCustomer);

expect(updateCustomer.emailAddress).toBe('another-address@test.com');

await shopClient.asUserWithCredentials('another-address@test.com', 'test');
const { me } = await shopClient.query<Codegen.MeQuery>(ME);

expect(me?.identifier).toBe('another-address@test.com');
});
});

describe('deletion', () => {
Expand Down
23 changes: 23 additions & 0 deletions packages/core/e2e/shop-auth.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,29 @@ describe('Updating email address without email verification', () => {
);
expect(activeCustomer!.emailAddress).toBe(NEW_EMAIL_ADDRESS);
});

it('normalizes updated email address', async () => {
await shopClient.asUserWithCredentials(NEW_EMAIL_ADDRESS, 'test');
const { requestUpdateCustomerEmailAddress } = await shopClient.query<
CodegenShop.RequestUpdateEmailAddressMutation,
CodegenShop.RequestUpdateEmailAddressMutationVariables
>(REQUEST_UPDATE_EMAIL_ADDRESS, {
password: 'test',
newEmailAddress: ' Not.Normal@test.com ',
});
successErrorGuard.assertSuccess(requestUpdateCustomerEmailAddress);
// Attempting to fix flakiness possibly caused by race condition on the event
// subscriber
await new Promise(resolve => setTimeout(resolve, 100));
expect(requestUpdateCustomerEmailAddress.success).toBe(true);
expect(sendEmailFn).toHaveBeenCalledTimes(1);
expect(sendEmailFn.mock.calls[0][0] instanceof IdentifierChangeEvent).toBe(true);

const { activeCustomer } = await shopClient.query<CodegenShop.GetActiveCustomerQuery>(
GET_ACTIVE_CUSTOMER,
);
expect(activeCustomer!.emailAddress).toBe('not.normal@test.com');
});
});

function getVerificationTokenPromise(): Promise<string> {
Expand Down
16 changes: 10 additions & 6 deletions packages/core/src/service/services/customer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,13 +308,16 @@ export class CustomerService {
});

if (hasEmailAddress(input)) {
input.emailAddress = normalizeEmailAddress(input.emailAddress);
if (input.emailAddress !== customer.emailAddress) {
const existingCustomerInChannel = await this.connection
.getRepository(ctx, Customer)
.createQueryBuilder('customer')
.leftJoin('customer.channels', 'channel')
.where('channel.id = :channelId', { channelId: ctx.channelId })
.andWhere('customer.emailAddress = :emailAddress', { emailAddress: input.emailAddress })
.andWhere('customer.emailAddress = :emailAddress', {
emailAddress: input.emailAddress,
})
.andWhere('customer.id != :customerId', { customerId: input.id })
.andWhere('customer.deletedAt is null')
.getOne();
Expand Down Expand Up @@ -566,6 +569,7 @@ export class CustomerService {
userId: ID,
newEmailAddress: string,
): Promise<boolean | EmailAddressConflictError> {
const normalizedEmailAddress = normalizeEmailAddress(newEmailAddress);
const userWithConflictingIdentifier = await this.userService.getUserByEmailAddress(
ctx,
newEmailAddress,
Expand All @@ -588,18 +592,18 @@ export class CustomerService {
type: HistoryEntryType.CUSTOMER_EMAIL_UPDATE_REQUESTED,
data: {
oldEmailAddress,
newEmailAddress,
newEmailAddress: normalizedEmailAddress,
},
});
if (this.configService.authOptions.requireVerification) {
user.getNativeAuthenticationMethod().pendingIdentifier = newEmailAddress;
user.getNativeAuthenticationMethod().pendingIdentifier = normalizedEmailAddress;
await this.userService.setIdentifierChangeToken(ctx, user);
this.eventBus.publish(new IdentifierChangeRequestEvent(ctx, user));
return true;
} else {
const oldIdentifier = user.identifier;
user.identifier = newEmailAddress;
customer.emailAddress = newEmailAddress;
user.identifier = normalizedEmailAddress;
customer.emailAddress = normalizedEmailAddress;
await this.connection.getRepository(ctx, User).save(user, { reload: false });
await this.connection.getRepository(ctx, Customer).save(customer, { reload: false });
this.eventBus.publish(new IdentifierChangeEvent(ctx, user, oldIdentifier));
Expand All @@ -609,7 +613,7 @@ export class CustomerService {
type: HistoryEntryType.CUSTOMER_EMAIL_UPDATE_VERIFIED,
data: {
oldEmailAddress,
newEmailAddress,
newEmailAddress: normalizedEmailAddress,
},
});
return true;
Expand Down

0 comments on commit 957d0ad

Please sign in to comment.