Skip to content

Commit

Permalink
fix(user-profile-management) add endpoints for user to edit profile d…
Browse files Browse the repository at this point in the history
…ata and change profile image
  • Loading branch information
MC-Knight committed Jul 19, 2024
1 parent c67cbca commit 0b6e258
Show file tree
Hide file tree
Showing 10 changed files with 3,797 additions and 4,910 deletions.
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

0 comments on commit 0b6e258

Please sign in to comment.