Skip to content

Commit

Permalink
fix(loopback4-example-shopping): prevent duplicate user email
Browse files Browse the repository at this point in the history
Prevent creation of user with email value that belongs to an existing user

fix #103

Signed-off-by: dougal83 <[email protected]>
  • Loading branch information
dougal83 authored and bajtos committed Jun 18, 2019
1 parent 491ba12 commit 889125c
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ describe('UserController', () => {
before('setupApplication', async () => {
({app, client} = await setupApplication());
});
before(migrateSchema);
before(createPasswordHasher);
before(givenAnExpiredToken);

Expand Down Expand Up @@ -114,6 +115,19 @@ describe('UserController', () => {
);
});

it('throws error for POST /users with an existing email', async () => {
await client
.post('/users')
.send(user)
.expect(200);
const res = await client
.post('/users')
.send(user)
.expect(409);

expect(res.body.error.message).to.equal('Email value is already taken');
});

it('returns a user with given id when GET /users/{id} is invoked', async () => {
const newUser = await createAUser();
delete newUser.password;
Expand Down Expand Up @@ -249,6 +263,10 @@ describe('UserController', () => {
await userRepo.deleteAll();
}

async function migrateSchema() {
await app.migrateSchema();
}

async function createAUser() {
const encryptedPassword = await passwordHasher.hashPassword(user.password);
const newUser = await userRepo.create(
Expand Down
19 changes: 14 additions & 5 deletions packages/shopping/src/controllers/user.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import {repository} from '@loopback/repository';
import {validateCredentials} from '../services/validator';
import {post, param, get, requestBody} from '@loopback/rest';
import {post, param, get, requestBody, HttpErrors} from '@loopback/rest';
import {User, Product} from '../models';
import {UserRepository} from '../repositories';
import {RecommenderService} from '../services/recommender.service';
Expand Down Expand Up @@ -52,11 +52,20 @@ export class UserController {
// encrypt the password
user.password = await this.passwordHasher.hashPassword(user.password);

// create the new user
const savedUser = await this.userRepository.create(user);
delete savedUser.password;
try {
// create the new user
const savedUser = await this.userRepository.create(user);
delete savedUser.password;

return savedUser;
return savedUser;
} catch (error) {
// MongoError 11000 duplicate key
if (error.code === 11000 && error.errmsg.includes('index: uniqueEmail')) {
throw new HttpErrors.Conflict('Email value is already taken');
} else {
throw error;
}
}
}

@get('/users/{userId}', {
Expand Down
15 changes: 14 additions & 1 deletion packages/shopping/src/models/user.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,20 @@
import {Entity, model, property, hasMany} from '@loopback/repository';
import {Order} from './order.model';

@model()
@model({
settings: {
indexes: {
uniqueEmail: {
keys: {
email: 1,
},
options: {
unique: true,
},
},
},
},
})
export class User extends Entity {
@property({
type: 'string',
Expand Down

0 comments on commit 889125c

Please sign in to comment.