-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: resend email route * fix: resendEmail tests and more * tournamentId validator * tournamentId typed better * added tests for resendEmail route * updated some tests accordingly * fix: reverted tournament changes * removed various errors and failes tests * refactor: put resend mail directly in the controller --------- Co-authored-by: Teddy Roncin <[email protected]>
- Loading branch information
Showing
8 changed files
with
197 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import { NextFunction, Request, Response } from 'express'; | ||
import Joi from 'joi'; | ||
import bcrpyt from 'bcryptjs'; | ||
import * as Sentry from '@sentry/node'; | ||
import { isNotAuthenticated } from '../../middlewares/authentication'; | ||
import { validateBody } from '../../middlewares/validation'; | ||
import * as validators from '../../utils/validators'; | ||
import { forbidden, success, unauthenticated } from '../../utils/responses'; | ||
import { Error as ResponseError } from '../../types'; | ||
import { fetchUser } from '../../operations/user'; | ||
import { sendValidationCode } from '../../services/email'; | ||
import logger from '../../utils/logger'; | ||
|
||
export default [ | ||
// Middlewares | ||
...isNotAuthenticated, | ||
validateBody( | ||
Joi.object({ | ||
username: validators.username.required(), | ||
email: validators.email.required(), | ||
password: validators.password.required(), | ||
}), | ||
), | ||
|
||
// Controller | ||
async (request: Request, response: Response, next: NextFunction) => { | ||
try { | ||
const { username, password } = request.body; | ||
|
||
// Fetch the user depending on the email or the username | ||
if (validators.username.validate(username).error) { | ||
return unauthenticated(response, ResponseError.InvalidCredentials); | ||
} | ||
|
||
const field = 'username'; | ||
|
||
const user = await fetchUser(username, field); | ||
|
||
// Checks if the user exists | ||
if (!user) { | ||
return unauthenticated(response, ResponseError.InvalidCredentials); | ||
} | ||
|
||
// Checks if the user doesn't already have its email confirmed | ||
if (!user.registerToken) { | ||
return forbidden(response, ResponseError.EmailAlreadyConfirmed); | ||
} | ||
|
||
// Compares the hash from the password given | ||
const isPasswordValid = await bcrpyt.compare(password, user.password); | ||
|
||
// If the password is not valid, rejects the request | ||
if (!isPasswordValid) { | ||
return unauthenticated(response, ResponseError.InvalidCredentials); | ||
} | ||
|
||
// Send registration token by mail | ||
// Don't send sync when it is not needed | ||
// If the mail is not sent, the error will be reported through Sentry | ||
// and staff may resend it manually | ||
sendValidationCode(user).catch((error) => { | ||
Sentry.captureException(error, { | ||
user: { | ||
id: user.id, | ||
username: user.username, | ||
email: user.email, | ||
}, | ||
}); | ||
logger.warn(error); | ||
}); | ||
return success(response, { | ||
sent: true, | ||
}); | ||
} catch (error) { | ||
return next(error); | ||
} | ||
}, | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import request from 'supertest'; | ||
import app from '../../src/app'; | ||
import * as userOperations from '../../src/operations/user'; | ||
import * as mailOperations from '../../src/services/email'; | ||
import { Error, User } from '../../src/types'; | ||
import database from '../../src/services/database'; | ||
import { sandbox } from '../setup'; | ||
import { createFakeUser } from '../utils'; | ||
|
||
describe('POST /auth/resendEmail', () => { | ||
const password = 'bonjour123456'; | ||
let user: User; | ||
let confirmedUser: User; | ||
|
||
before(async () => { | ||
// Creates fake user with email | ||
confirmedUser = await createFakeUser({ password }); | ||
user = await createFakeUser({ password, confirmed: false }); | ||
}); | ||
|
||
beforeEach(() => { | ||
sandbox.stub(mailOperations, 'sendEmail'); | ||
}); | ||
|
||
after(async () => { | ||
// Delete the user created | ||
await database.user.deleteMany(); | ||
}); | ||
|
||
it('should return a bad request because of incorrect body', async () => { | ||
await request(app) | ||
.post('/auth/resendEmail') | ||
.send({ | ||
fake: 'fake', | ||
}) | ||
.expect(400, { error: Error.InvalidUsername }); | ||
}); | ||
|
||
it('should return an error as incorrect credentials (wrong password)', async () => { | ||
await request(app) | ||
.post('/auth/resendEmail') | ||
.send({ | ||
username: user.username, | ||
email: user.email, | ||
password: 'wrongpassword', | ||
}) | ||
.expect(401, { error: Error.InvalidCredentials }); | ||
}); | ||
|
||
it('should return an internal server error', async () => { | ||
sandbox.stub(userOperations, 'fetchUser').throws('Unexpected error'); | ||
|
||
await request(app) | ||
.post('/auth/resendEmail') | ||
.send({ | ||
username: user.username, | ||
email: user.email, | ||
password, | ||
}) | ||
.expect(500, { error: Error.InternalServerError }); | ||
}); | ||
|
||
it('should return an email already confirmed error', async () => { | ||
await request(app) | ||
.post('/auth/resendEmail') | ||
.send({ | ||
username: confirmedUser.username, | ||
email: confirmedUser.email, | ||
password, | ||
}) | ||
.expect(403, { error: Error.EmailAlreadyConfirmed }); | ||
}); | ||
|
||
it('should return a valid response', async () => { | ||
await request(app) | ||
.post('/auth/resendEmail') | ||
.send({ | ||
username: user.username, | ||
email: user.email, | ||
password, | ||
}) | ||
.expect(200); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters