Skip to content

Commit

Permalink
TST - convergeance and reset password
Browse files Browse the repository at this point in the history
  • Loading branch information
juliecoust committed Jan 26, 2024
1 parent fd5f517 commit 61350f0
Show file tree
Hide file tree
Showing 6 changed files with 318 additions and 20 deletions.
13 changes: 9 additions & 4 deletions src/domain/entities/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,22 @@ export interface UserUpdateModel {
}

// the user response model
export interface UserResponseModel {
export interface UserResponseModel extends PublicUserModel {
confirmation_code?: string | null;
reset_password_code?: string | null;
}
export interface PublicUserModel {
user_id: number;
first_name: string;
last_name: string;
email: string;
valid_email: boolean;
confirmation_code?: string | null;
reset_password_code?: string | null; //TODO UTILE?
is_admin: boolean;
organisation: string;
country: string;
user_planned_usage: string;
user_creation_date: string; //YYYY-MM-DD HH:MM:SS TimeStamp
user_creation_date: string;
}
export interface PrivateUserModel extends PublicUserModel, UserResponseModel {
password_hash?: string;
}
4 changes: 2 additions & 2 deletions src/domain/interfaces/repositories/user-repository.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

import { AuthUserCredentialsModel, DecodedToken, ChangeCredentialsModel } from "../../entities/auth";
import { UserRequesCreationtModel, UserResponseModel, UserRequestModel, UserUpdateModel } from "../../entities/user";
import { UserRequesCreationtModel, UserResponseModel, UserRequestModel, UserUpdateModel, PublicUserModel, PrivateUserModel } from "../../entities/user";
export interface UserRepository {
changePassword(user_to_update: ChangeCredentialsModel): Promise<number>;
getUser(user: UserRequestModel): Promise<UserResponseModel | null>;
Expand All @@ -16,5 +16,5 @@ export interface UserRepository {
generateResetPasswordToken(user: UserRequestModel): string;
verifyResetPasswordToken(reset_password_token: string): DecodedToken | null;
setResetPasswordCode(user: UserUpdateModel): Promise<number>;
toPublicUser(createdUser: UserResponseModel): UserResponseModel;
toPublicUser(createdUser: PrivateUserModel): PublicUserModel;
}
8 changes: 4 additions & 4 deletions src/domain/repositories/user-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { CryptoWrapper } from "../../infra/cryptography/crypto-wrapper";
import { UserDataSource } from "../../data/interfaces/data-sources/user-data-source";
import { AuthUserCredentialsModel, ChangeCredentialsModel, DecodedToken } from "../entities/auth";
import { UserResponseModel, UserRequesCreationtModel, UserRequestModel, UserUpdateModel } from "../entities/user";
import { UserResponseModel, UserRequesCreationtModel, UserRequestModel, UserUpdateModel, PublicUserModel, PrivateUserModel } from "../entities/user";
import { UserRepository } from "../interfaces/repositories/user-repository";
import { JwtWrapper } from "../../infra/auth/jwt-wrapper";

Expand Down Expand Up @@ -144,8 +144,8 @@ export class UserRepositoryImpl implements UserRepository {
return user.is_admin
}

toPublicUser(createdUser: UserResponseModel): UserResponseModel {
const publicUser: UserResponseModel = {
toPublicUser(createdUser: PrivateUserModel): PublicUserModel {
const publicUser: PublicUserModel = {
user_id: createdUser.user_id,
first_name: createdUser.first_name,
last_name: createdUser.last_name,
Expand All @@ -155,7 +155,7 @@ export class UserRepositoryImpl implements UserRepository {
organisation: createdUser.organisation,
country: createdUser.country,
user_planned_usage: createdUser.user_planned_usage,
user_creation_date: ""
user_creation_date: createdUser.user_creation_date
}

return publicUser
Expand Down
13 changes: 6 additions & 7 deletions src/presentation/routers/auth-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ export default function AuthRouter(
.json({ response: "Reset password request email sent." });
} catch (err) {
console.log(err)
if (err.message === "User does not exist") res.status(200).send({ errors: ["Reset password request email sent."] })
else if (err.message === "User email is not validated") res.status(200).send({ errors: ["Reset password request email sent."] })
if (err.message === "User does not exist") res.status(200).send({ response: "Reset password request email sent." })
else if (err.message === "User email is not validated") res.status(200).send({ response: "Reset password request email sent." })
else if (err.message === "Can't set password reset code") res.status(500).send({ errors: ["Can't reset password"] })
else if (err.message === "Can't find updated user") res.status(500).send({ errors: ["Can't reset password"] })
else res.status(500).send({ errors: ["Can't reset password"] })
Expand All @@ -121,17 +121,16 @@ export default function AuthRouter(
// reset password confirm
router.put('/password/reset', async (req: Request, res: Response) => {
try {
console.log("req.body", req.body)
await resetPasswordUseCase.execute(req.body)
res
.status(200)
.json({ response: "Password sucessfully reset, please login" });
} catch (err) {
console.log(err)
if (err.message === "Token is not valid") res.status(401).send({ errors: ["Can't change password"] })
if (err.message === "No token provided") res.status(401).send({ errors: ["Can't change password"] })
if (err.message === "User does not exist or token is not valid") res.status(404).send({ errors: ["Can't change password"] })
if (err.message === "User email is not validated") res.status(403).send({ errors: ["Can't change password"] })
if (err.message === "Token is not valid") res.status(401).send({ errors: ["Can't reset password"] })
if (err.message === "No token provided") res.status(401).send({ errors: ["Can't reset password"] })
if (err.message === "User does not exist or token is not valid") res.status(404).send({ errors: ["Can't reset password"] })
if (err.message === "User email is not validated") res.status(403).send({ errors: ["Can't reset password"] })
else res.status(500).send({ errors: ["Can't reset password"] })
}
})
Expand Down
112 changes: 110 additions & 2 deletions test/domain/repositories/user-repository.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//test/domain/repositories/user-repository.test.ts
import { UserDataSource } from "../../../src/data/interfaces/data-sources/user-data-source";
import { AuthUserCredentialsModel, ChangeCredentialsModel, DecodedToken } from "../../../src/domain/entities/auth";
import { UserRequesCreationtModel, UserRequestModel, UserResponseModel, UserUpdateModel } from "../../../src/domain/entities/user";
import { PrivateUserModel, PublicUserModel, UserRequesCreationtModel, UserRequestModel, UserResponseModel, UserUpdateModel } from "../../../src/domain/entities/user";
import { UserRepository } from "../../../src/domain/interfaces/repositories/user-repository";
import { UserRepositoryImpl } from "../../../src/domain/repositories/user-repository";
import { BcryptAdapter } from "../../../src/infra/cryptography/bcript"
Expand Down Expand Up @@ -213,8 +213,9 @@ describe("User Repository", () => {

const result = await userRepository.verifyValidationToken(InputData);
expect(result).toBe(OutputData)

expect(jwtAdapter.verify).toHaveBeenCalledWith(InputData, TEST_VALIDATION_TOKEN_SECRET)
});

test("should handle error and return null", async () => {
const InputData: string = "validation_token"

Expand All @@ -226,6 +227,46 @@ describe("User Repository", () => {
});
});

describe("verifyResetPasswordToken", () => {
test("Should decode token and return it", async () => {
const InputData: string = "validation_token"

const OutputData: DecodedToken = {
user_id: 1,
last_name: "Smith",
first_name: "John",
email: "[email protected]",
valid_email: false,
confirmation_code: "123456",
is_admin: false,
organisation: "LOV",
country: "France",
user_planned_usage: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
user_creation_date: '2023-08-01 10:30:00',

iat: 1693237789,
exp: 1724795389
}

jest.spyOn(jwtAdapter, "verify").mockImplementation(() => Promise.resolve(OutputData))

const result = await userRepository.verifyResetPasswordToken(InputData);
expect(result).toBe(OutputData)
expect(jwtAdapter.verify).toHaveBeenCalledWith(InputData, TEST_RESET_PASSWORD_TOKEN_SECRET)

});

test("should handle error and return null", async () => {
const InputData: string = "validation_token"

jest.spyOn(jwtAdapter, "verify").mockImplementation(() => { throw new Error() })

const result = await userRepository.verifyResetPasswordToken(InputData);
expect(result).toBe(null)

});
});

describe("UpdateUser", () => {

test("Things to update : any user try to validate his unvalidated account", async () => {
Expand Down Expand Up @@ -499,6 +540,39 @@ describe("User Repository", () => {
});
});

describe("GenerateResetPasswordToken", () => {
test("Should return generated token ", async () => {
const User: UserRequestModel = {
user_id: 1,
reset_password_code: "123456",
}

jest.spyOn(jwtAdapter, "sign").mockImplementation(() => { return "reset_password_token" })

const result = await userRepository.generateResetPasswordToken(User);

expect(jwtAdapter.sign).toHaveBeenCalledWith(
{ user_id: 1, reset_password_code: "123456" },
TEST_RESET_PASSWORD_TOKEN_SECRET,
{ expiresIn: '3h' })
expect(result).toBe("reset_password_token")

});
});

describe("setResetPasswordCode", () => {
test("Should set reset password code", async () => {
const inputData: UserUpdateModel = {
user_id: 1,
}

jest.spyOn(mockUserDataSource, "updateOne").mockImplementation(() => Promise.resolve(1))
const result = await userRepository.setResetPasswordCode(inputData);
expect(result).toBe(1)
expect(mockUserDataSource.updateOne).toHaveBeenCalledWith({ user_id: 1, reset_password_code: expect.any(String) })
});
});

describe("changePassword", () => {
test("Should return 1 in nominal case", async () => {

Expand Down Expand Up @@ -536,4 +610,38 @@ describe("User Repository", () => {
});
});

describe("toPublicUser", () => {
test("Should return one user", async () => {
const inputData: PrivateUserModel = {
user_id: 1,
last_name: "Smith",
first_name: "John",
email: "[email protected]",
valid_email: true,
is_admin: false,
organisation: "LOV",
country: "France",
user_planned_usage: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
user_creation_date: '2023-08-01 10:30:00',
password_hash: "code",
confirmation_code: "code",
reset_password_code: "code"
}

const expectedData: PublicUserModel = {
user_id: 1,
first_name: 'John',
last_name: 'Smith',
email: '[email protected]',
valid_email: true,
is_admin: false,
organisation: 'LOV',
country: 'France',
user_planned_usage: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
user_creation_date: '2023-08-01 10:30:00'
}
const result: PublicUserModel = userRepository.toPublicUser(inputData);
expect(result).toStrictEqual(expectedData)
});
})
})
Loading

0 comments on commit 61350f0

Please sign in to comment.