Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix user profile managment #124

Merged
merged 1 commit into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8,383 changes: 3,575 additions & 4,808 deletions model.nlp

Large diffs are not rendered by default.

154 changes: 79 additions & 75 deletions src/__test__/userServices.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { cleanDatabase } from './test-assets/DatabaseCleanup';
import { v4 as uuid } from 'uuid';
import { dbConnection } from '../startups/dbConnection';

import bcrypt from 'bcrypt'
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';

const userId = uuid();
Expand Down Expand Up @@ -132,66 +132,78 @@ describe('User service Test', () => {
});

it('should Login a user, with valid credentials', async () => {
const res = await request(app)
.post('/user/login')
.send({
email: '[email protected]',
password: 'password',
});
const res = await request(app).post('/user/login').send({
email: '[email protected]',
password: 'password',
});
// Assert
expect(res.status).toBe(200);
expect(res.body.data.token).toBeDefined();
});

it('should send OTP, if 2FA is enabled', async () => {
const res = await request(app)
.post('/user/login')
.send({
email: '[email protected]',
password: 'password',
});
const res = await request(app).post('/user/login').send({
email: '[email protected]',
password: 'password',
});
// Assert
expect(res.status).toBe(200);
expect(res.body.data.message).toBe('Please provide the OTP sent to your email or phone');
});

it('should not Login a user, with invalid credentials', async () => {
const res = await request(app)
.post('/user/login')
.send({
email: '[email protected]',
password: 'passwo',
});
const res = await request(app).post('/user/login').send({
email: '[email protected]',
password: 'passwo',
});
// Assert
expect(res.status).toBe(401);
});

it('should not login User if user email is not verified', async () => {
const res = await request(app)
.post('/user/login')
.send({
email: '[email protected]',
password: 'password',
});
const res = await request(app).post('/user/login').send({
email: '[email protected]',
password: 'password',
});

expect(res.status).toBe(400);
expect(res.body.message).toBe("Please verify your account");
expect(res.body.message).toBe('Please verify your account');
});

it('should not login User if user is currently suspended', async () => {
const res = await request(app)
.post('/user/login')
.send({
email: sampleUser1.email,
password: sampleUser1.password,
});
const res = await request(app).post('/user/login').send({
email: sampleUser1.email,
password: sampleUser1.password,
});

expect(res.status).toBe(400);
expect(res.body.message).toBe("Your account has been suspended");
expect(res.body.message).toBe('Your account has been suspended');
});
});

describe('User Profile update', () => {
it('should get user information', async () => {
const res = await request(app)
.get('/user/profile')
.set('Authorization', `Bearer ${getAccessToken(userId, sampleUser.email)}`);

expect(res.status).toBe(200);
expect(res.body.status).toBe('success');
expect(res.body.data.code).toBe(200);
expect(res.body.data.message).toBe('profile fetched successfully');
});

it('should get user information', async () => {
const res = await request(app)
.put('/user/profile')
.send({ images: [] })
.set('Authorization', `Bearer ${getAccessToken(userId, sampleUser.email)}`);

expect(res.status).toBe(400);
expect(res.body.status).toBe('error');
expect(res.body.message).toBe("Cannot read properties of undefined (reading 'length')");
});

it('should update user profile', async () => {
const res = await request(app)
.put('/user/update')
Expand All @@ -200,7 +212,6 @@ describe('User service Test', () => {
lastName: 'Doe',
gender: 'Male',
phoneNumber: '0789412421',
photoUrl: 'photo.jpg',
})
.set('Authorization', `Bearer ${getAccessToken(userId, sampleUser.email)}`);

Expand All @@ -220,7 +231,7 @@ describe('User service Test', () => {
.put('/user/update')
.send({
firstName: 'firstName updated',
lastName: 'lastName updated'
lastName: 'lastName updated',
})
.set('Authorization', `Bearer ${getAccessToken(userId, sampleUser.email)}`);

Expand All @@ -230,58 +241,51 @@ describe('User service Test', () => {

describe('User Reset Password', () => {
it('should return response error, if no email and userID provided', async () => {
const respond = await request(app)
.post('/user/password/reset');
const respond = await request(app).post('/user/password/reset');

expect(respond.status).toBe(400);
});

it('should not reset password, for no existing Users', async () => {
const respond = await request(app)
.post('/user/password/reset')
.query({
email: '[email protected]',
userid: uuid()
});
const respond = await request(app).post('/user/password/reset').query({
email: '[email protected]',
userid: uuid(),
});

expect(respond.status).toBe(404);
});

it('should not reset password, if no new password sent', async () => {
const respond = await request(app)
.post('/user/password/reset')
.query({
email: sampleUser.email,
userid: sampleUser.id
});
const respond = await request(app).post('/user/password/reset').query({
email: sampleUser.email,
userid: sampleUser.id,
});

expect(respond.status).toBe(400);
expect(respond.body.message).toBe('Please provide all required fields');
});

it('should not reset password, if new password doesn\'t match password in confirmPassword field', async () => {
it("should not reset password, if new password doesn't match password in confirmPassword field", async () => {
const respond = await request(app)
.post('/user/password/reset')
.query({
email: sampleUser.email,
userid: sampleUser.id
userid: sampleUser.id,
})
.send({
newPassword: 'new-password',
confirmPassword: 'password'
confirmPassword: 'password',
});

expect(respond.status).toBe(400);
expect(respond.body.message).toBe('new password must match confirm password');
});

it('should not reset password, for incorrect user id syntax (invalid uuid)', async () => {
const respond = await request(app)
.post('/user/password/reset')
.query({
email: sampleUser.email,
userid: 'invalid-=uuid'
});
const respond = await request(app).post('/user/password/reset').query({
email: sampleUser.email,
userid: 'invalid-=uuid',
});

expect(respond.status).toBe(500);
});
Expand All @@ -290,11 +294,11 @@ describe('User service Test', () => {
.post('/user/password/reset')
.query({
email: sampleUser.email,
userid: sampleUser.id
userid: sampleUser.id,
})
.send({
newPassword: 'new-password',
confirmPassword: 'new-password'
confirmPassword: 'new-password',
});

expect(respond.status).toBe(200);
Expand All @@ -304,22 +308,19 @@ describe('User service Test', () => {

describe('User password reset link', () => {
it('should send link to reset password', async () => {
const response = await request(app)
.post('/user/password/reset/link')
.query({ email: sampleUser.email });
const response = await request(app).post('/user/password/reset/link').query({ email: sampleUser.email });

expect(response.status).toBe(200);
});

it('should not send link to reset password, if no email provided', async () => {
const response = await request(app)
.post('/user/password/reset/link');
const response = await request(app).post('/user/password/reset/link');

expect(response.status).toBe(400);
expect(response.body.message).toBe('Missing required field');
});

it('should not send link to reset password, if email doesn\'t exist in DB', async () => {
it("should not send link to reset password, if email doesn't exist in DB", async () => {
const response = await request(app)
.post('/user/password/reset/link')
.query({ email: '[email protected]' });
Expand All @@ -330,7 +331,6 @@ describe('User service Test', () => {
});

describe('Start@FAProcess', () => {

it('should return 400 if not sent email in body on enabling 2fa', async () => {
const data = {};

Expand Down Expand Up @@ -359,7 +359,10 @@ describe('User service Test', () => {
const res = await request(app).post('/user/enable-2fa').send(data);

expect(res.status).toBe(200);
expect(res.body).toEqual({ status: 'success', message: 'Two factor authentication enabled successfully' });
expect(res.body.status).toBe('success');
expect(res.body.data.code).toBe(200);
expect(res.body.data.message).toBe('Two factor authentication enabled successfully');
expect(res.body.data.profile.twoFactorEnabled).toBe(true);
});

it('should return 400 if not sent email in body on disabling 2fa', async () => {
Expand Down Expand Up @@ -390,7 +393,10 @@ describe('User service Test', () => {
const res = await request(app).post('/user/disable-2fa').send(data);

expect(res.status).toBe(200);
expect(res.body).toEqual({ status: 'success', message: 'Two factor authentication disabled successfully' });
expect(res.body.status).toBe('success');
expect(res.body.data.code).toBe(200);
expect(res.body.data.message).toBe('Two factor authentication disabled successfully');
expect(res.body.data.profile.twoFactorEnabled).toBe(false);
});

it('should return 400 if not sent email and otp in body on verifying OTP', async () => {
Expand Down Expand Up @@ -454,12 +460,10 @@ describe('User service Test', () => {
});

it('should login user, if OTP provided is valid', async () => {
const res = await request(app)
.post('/user/verify-otp')
.send({
email: sampleUser3.email,
otp: '123456',
});
const res = await request(app).post('/user/verify-otp').send({
email: sampleUser3.email,
otp: '123456',
});

expect(res.status).toBe(200);
expect(res.body.data.token).toBeDefined();
Expand Down
12 changes: 11 additions & 1 deletion src/controllers/authController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { deactivateUserService } from '../services/updateUserStatus/deactivateUs
import { userProfileUpdateServices } from '../services/userServices/userProfileUpdateServices';
import getAllUsers from '../services/userServices/getAllUsers';
import getUserById from '../services/userServices/getUserById';
import getUserProfile from '../services/userServices/getUserProfile';
import userUpdateProfilePicture from '../services/userServices/userUpdateProfileImage';

export const userRegistration = async (req: Request, res: Response) => {
await userRegistrationService(req, res);
Expand Down Expand Up @@ -76,4 +78,12 @@ export const getAllUsersController = async (req: Request, res: Response) => {

export const getUserByIdController = async (req: Request, res: Response) => {
await getUserById(req, res);
};
};

export const getUserProfileController = async (req: Request, res: Response) => {
await getUserProfile(req, res);
};

export const userUpdateProfilePictureController = async (req: Request, res: Response) => {
await userUpdateProfilePicture(req, res);
};
5 changes: 5 additions & 0 deletions src/routes/UserRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@ import {
logout,
getAllUsersController,
getUserByIdController,
getUserProfileController,
userUpdateProfilePictureController,
} from '../controllers';

import { activateUser, disactivateUser, userProfileUpdate } from '../controllers/index';
import { hasRole } from '../middlewares/roleCheck';
import upload from '../middlewares/multer';
import passport from 'passport';
import '../utils/auth';
import { start2FAProcess } from '../services/userServices/userStartTwoFactorAuthProcess';
Expand All @@ -43,6 +46,8 @@ router.post('/deactivate', authMiddleware as RequestHandler, hasRole('ADMIN'), d
router.post('/password/reset', userPasswordReset);
router.post('/password/reset/link', sendPasswordResetLink);
router.put('/update', authMiddleware as RequestHandler, userProfileUpdate);
router.get('/profile', authMiddleware as RequestHandler, getUserProfileController);
router.put('/profile', authMiddleware as RequestHandler, upload.array('images', 1), userUpdateProfilePictureController);

router.get('/google-auth', passport.authenticate('google', { scope: ['profile', 'email'] }));
router.get(
Expand Down
1 change: 1 addition & 0 deletions src/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export * from './userServices/userResendOTP';
export * from './userServices/logoutServices';
export * from './userServices/userProfileUpdateServices';


// Vendor product services
export * from './productServices/createProduct';
export * from './productServices/updateProduct';
Expand Down
18 changes: 18 additions & 0 deletions src/services/userServices/getUserProfile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Request, Response } from 'express';
import { responseError, responseSuccess } from '../../utils/response.utils';
import { UserInterface } from '../../entities/User';

const getUserProfile = async (req: Request, res: Response) => {
try {
const user = req.user;
// eslint-disable-next-line no-unused-vars
const { password, twoFactorCode, twoFactorCodeExpiresAt, ...safeUser } = user as UserInterface;
responseSuccess(res, 200, 'profile fetched successfully', { profile: safeUser });
return;
} catch (error) {
responseError(res, 400, (error as Error).message);
return;
}
};

export default getUserProfile;
Loading
Loading