-
Notifications
You must be signed in to change notification settings - Fork 87
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(auth.client): (1) extract email validation and send login ot…
…p flow to Typescript (#2084) * feat(AdminAuthService): add checkIsEmailAllowed service function * ref: condense vm.checkEmail and vm.checkUser into single vm.login fn * feat(AdminAuthService): add sendLoginOtp function * ref: use AdminAuthService.sendLoginOtp * ref: rename AdminAuthService to AuthService better fit API prefix * feat: remove all catch transformations from AuthService not needed, may interfere with React migration. Should just handle it in the caller # Conflicts: # src/public/modules/users/controllers/authentication.client.controller.js # src/public/services/AuthService.ts * test(AuthService): unit tests for checkIsEmailAllowed + sendLoginOtp * feat: remove unused functions from old auth.client * fix(auth.client.ctl): correctly retrieve error msg when sendOtp fails * test(AuthService): add clarity to test block Co-authored-by: tshuli <[email protected]> * feat(AuthService): remove throw documentation on sendLoginOtp Co-authored-by: tshuli <[email protected]>
- Loading branch information
Showing
5 changed files
with
140 additions
and
77 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
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,33 @@ | ||
import axios from 'axios' | ||
import { Opaque } from 'type-fest' | ||
|
||
// Exported for testing. | ||
export const AUTH_ENDPOINT = '/api/v3/auth' | ||
|
||
type Email = Opaque<string, 'Email'> | ||
|
||
/** | ||
* Check whether the given email string is from a whitelisted email domain. | ||
* @param email the email to check | ||
* @returns original email if email is valid | ||
*/ | ||
export const checkIsEmailAllowed = async (email: string): Promise<Email> => { | ||
return axios | ||
.post(`${AUTH_ENDPOINT}/email/validate`, { | ||
email: email.toLowerCase(), | ||
}) | ||
.then(() => email as Email) | ||
} | ||
|
||
/** | ||
* Sends login OTP to given email | ||
* @param email email to send login OTP to | ||
* @returns success string if login OTP is sent successfully | ||
*/ | ||
export const sendLoginOtp = async (email: Email): Promise<string> => { | ||
return axios | ||
.post<string>(`${AUTH_ENDPOINT}/otp/generate`, { | ||
email: email.toLowerCase(), | ||
}) | ||
.then(({ data }) => data) | ||
} |
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,60 @@ | ||
import axios from 'axios' | ||
import { mocked } from 'ts-jest/utils' | ||
import { Opaque } from 'type-fest' | ||
|
||
import { | ||
AUTH_ENDPOINT, | ||
checkIsEmailAllowed, | ||
sendLoginOtp, | ||
} from '../AuthService' | ||
|
||
jest.mock('axios') | ||
|
||
const MockAxios = mocked(axios, true) | ||
|
||
// Duplicated here instead of exporting from AuthService to prevent production | ||
// code from casting to Email type without going through a type guard/validator. | ||
type TestEmail = Opaque<string, 'Email'> | ||
|
||
describe('AuthService', () => { | ||
describe('checkIsEmailAllowed', () => { | ||
const EXPECTED_POST_ENDPOINT = `${AUTH_ENDPOINT}/email/validate` | ||
|
||
it('should return given email argument when email is allowed', async () => { | ||
// Arrange | ||
const mockEmail = '[email protected]' | ||
MockAxios.post.mockResolvedValueOnce({ status: 200 }) | ||
|
||
// Act | ||
const actual = await checkIsEmailAllowed(mockEmail) | ||
|
||
// Assert | ||
expect(actual).toEqual(mockEmail) | ||
expect(MockAxios.post).toHaveBeenCalledWith(EXPECTED_POST_ENDPOINT, { | ||
email: mockEmail.toLowerCase(), | ||
}) | ||
}) | ||
}) | ||
|
||
describe('sendLoginOtp', () => { | ||
const EXPECTED_POST_ENDPOINT = `${AUTH_ENDPOINT}/otp/generate` | ||
|
||
it('should return success string when OTP is successfully generated', async () => { | ||
// Arrange | ||
const mockEmail = '[email protected]' | ||
const mockSuccessStr = 'yippee ki yay' | ||
MockAxios.post.mockResolvedValueOnce({ | ||
data: mockSuccessStr, | ||
}) | ||
|
||
// Act | ||
const actual = await sendLoginOtp(mockEmail as TestEmail) | ||
|
||
// Assert | ||
expect(actual).toEqual(mockSuccessStr) | ||
expect(MockAxios.post).toHaveBeenCalledWith(EXPECTED_POST_ENDPOINT, { | ||
email: mockEmail.toLowerCase(), | ||
}) | ||
}) | ||
}) | ||
}) |