Skip to content

Commit

Permalink
Merge pull request #1772 from filipedeschamps/fix/patch-with-duplicat…
Browse files Browse the repository at this point in the history
…e-email-and-username

Sempre validar se `username` é único antes de validar o mesmo para o `email`
  • Loading branch information
aprendendofelipe authored Aug 1, 2024
2 parents dcadcea + fe97166 commit c8e7d6e
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 17 deletions.
37 changes: 20 additions & 17 deletions models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -405,24 +405,27 @@ async function validateUniqueUser(userData, options) {

const results = await database.query(query, options);

if (results.rowCount > 0) {
const isSameUsername = results.rows[0].username.toLowerCase() === userData.username?.toLowerCase();
if (isSameUsername) {
throw new ValidationError({
message: `O "username" informado já está sendo usado.`,
stack: new Error().stack,
errorLocationCode: `MODEL:USER:VALIDATE_UNIQUE_USERNAME:ALREADY_EXISTS`,
key: 'username',
});
} else {
throw new ValidationError({
message: `O email informado já está sendo usado.`,
stack: new Error().stack,
errorLocationCode: `MODEL:USER:VALIDATE_UNIQUE_EMAIL:ALREADY_EXISTS`,
key: 'email',
});
}
if (!results.rowCount) return;

const isSameUsername = results.rows.some(
({ username }) => username.toLowerCase() === userData.username?.toLowerCase(),
);

if (isSameUsername) {
throw new ValidationError({
message: `O "username" informado já está sendo usado.`,
stack: new Error().stack,
errorLocationCode: `MODEL:USER:VALIDATE_UNIQUE_USERNAME:ALREADY_EXISTS`,
key: 'username',
});
}

throw new ValidationError({
message: `O email informado já está sendo usado.`,
stack: new Error().stack,
errorLocationCode: `MODEL:USER:VALIDATE_UNIQUE_EMAIL:ALREADY_EXISTS`,
key: 'email',
});
}

async function hashPasswordInObject(userObject) {
Expand Down
58 changes: 58 additions & 0 deletions tests/integration/api/v1/users/[username]/patch.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,64 @@ describe('PATCH /api/v1/users/[username]', () => {
expect(foundUser.updated_at.toISOString()).toBe(responseBody.updated_at);
});

test('Patching itself with duplicate "email" and "username" should only return "username" error', async () => {
await orchestrator.createUser({ username: 'usernameStoredPreviously' });
await orchestrator.createUser({ email: 'this_email_already_exists@example.com' });
await orchestrator.createUser({ username: 'usernameStoredLater' });

const usersRequestBuilder = new RequestBuilder('/api/v1/users/');
const defaultUser = await usersRequestBuilder.buildUser();
await orchestrator.deleteAllEmails();

const { response, responseBody } = await usersRequestBuilder.patch(defaultUser.username, {
email: 'this_email_already_exists@example.com',
username: 'usernameStoredPreviously',
});
expect.soft(response.status).toBe(400);

expect(responseBody).toStrictEqual({
status_code: 400,
name: 'ValidationError',
message: 'O "username" informado já está sendo usado.',
action: 'Ajuste os dados enviados e tente novamente.',
error_location_code: 'MODEL:USER:VALIDATE_UNIQUE_USERNAME:ALREADY_EXISTS',
error_id: responseBody.error_id,
request_id: responseBody.request_id,
key: 'username',
});
expect(uuidVersion(responseBody.error_id)).toBe(4);
expect(uuidVersion(responseBody.request_id)).toBe(4);

const { response: response2, responseBody: responseBody2 } = await usersRequestBuilder.patch(
defaultUser.username,
{
email: 'this_email_already_exists@example.com',
username: 'usernameStoredLater',
},
);
expect.soft(response2.status).toBe(400);

expect(responseBody2).toStrictEqual({
status_code: 400,
name: 'ValidationError',
message: 'O "username" informado já está sendo usado.',
action: 'Ajuste os dados enviados e tente novamente.',
error_location_code: 'MODEL:USER:VALIDATE_UNIQUE_USERNAME:ALREADY_EXISTS',
error_id: responseBody2.error_id,
request_id: responseBody2.request_id,
key: 'username',
});
expect(uuidVersion(responseBody2.error_id)).toBe(4);
expect(uuidVersion(responseBody2.request_id)).toBe(4);

const confirmationEmail = await orchestrator.getLastEmail();
expect(confirmationEmail).toBeNull();

const foundUser = await user.findOneById(defaultUser.id);
expect(foundUser.email).toBe(defaultUser.email);
expect(foundUser.updated_at).toStrictEqual(defaultUser.updated_at);
});

test('Patching itself with another "email"', async () => {
let defaultUser = await orchestrator.createUser({
email: 'original@email.com',
Expand Down

0 comments on commit c8e7d6e

Please sign in to comment.