Skip to content

Commit

Permalink
ft-sign in functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
Ndevu12 committed May 2, 2024
1 parent a55431c commit f8ffab6
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 20 deletions.
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@
"@types/swagger-ui-express": "^4.1.6",
"bcrypt": "^5.1.1",
"class-validator": "^0.14.1",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.19.2",
"express-winston": "^4.2.0",
"highlight.js": "^11.9.0",
"jsend": "^1.1.0",
"jsonwebtoken": "^9.0.2",
"morgan": "^1.10.0",
"nodemon": "^3.1.0",
"pg": "^8.11.5",
Expand All @@ -48,13 +50,15 @@
"@eslint/js": "^9.1.1",
"@types/bcrypt": "^5.0.2",
"@types/body-parser": "^1.19.5",
"@types/cookie-parser": "^1.4.7",
"@types/cors": "^2.8.17",
"@types/dotenv": "^8.2.0",
"@types/eslint": "^8.56.10",
"@types/eslint__js": "^8.42.3",
"@types/express": "^4.17.21",
"@types/jest": "^29.5.12",
"@types/jsend": "^1.0.32",
"@types/jsonwebtoken": "^9.0.6",
"@types/morgan": "^1.9.9",
"@types/node": "^20.12.7",
"@types/reflect-metadata": "^0.1.0",
Expand All @@ -75,4 +79,4 @@
"typescript": "^5.4.5",
"typescript-eslint": "^7.7.1"
}
}
}
26 changes: 13 additions & 13 deletions src/__test__/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,25 @@ afterAll(async () => {
server.close();
});



describe('GET /', () => {
it('This is a testing route that returns', done => {
request(app)
.get('/api/v1/status')
.expect(200)
.expect('Content-Type', /json/)
.expect({
status: 'success',
data: {
code: 202,
message: 'This is a testing route that returns: 202'
}
}, done);
.expect(
{
status: 'success',
data: {
code: 202,
message: 'This is a testing route that returns: 202',
},
},
done
);
});
});

describe('POST /user/register', () => {
it('should register a new user and then delete it', async () => {
// Arrange
Expand All @@ -49,9 +51,7 @@ describe('POST /user/register', () => {
};

// Act
const res = await request(app)
.post('/user/register')
.send(newUser);
const res = await request(app).post('/user/register').send(newUser);

// Assert
expect(res.status).toBe(201);
Expand All @@ -64,4 +64,4 @@ describe('POST /user/register', () => {
await userRepository.remove(user);
}
});
});
});
31 changes: 31 additions & 0 deletions src/__test__/signin.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import request from 'supertest';
import { app, server } from '../index'; // update this with the path to your app file
import { createConnection, getConnection, getConnectionOptions } from 'typeorm';

beforeAll(async () => {
// Connect to the test database
const connectionOptions = await getConnectionOptions();
await createConnection({ ...connectionOptions, name: 'testConnection' });
});

afterAll(async () => {
await getConnection('testConnection').close();
server.close();
});

describe('POST /user/signin', () => {
it('should sign in a user', async () => {
// Arrange
const userSignin = {
email: '[email protected]',
password: 'ndevu',
};

// Act
const res = await request(app).post('/user/signin').send(userSignin);

// Assert
expect(res.status).toBe(200);
expect(res.body).toEqual({ Message: 'signed in successfully', userObject: { accessToken: expect.any(String) } });
});
});
3 changes: 2 additions & 1 deletion src/controllers/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { UserController } from './authController';
import signinAndOutController from './signinAndOutController';

export{UserController};
export { UserController, signinAndOutController };
57 changes: 57 additions & 0 deletions src/controllers/signinAndOutController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Request, Response } from 'express';
import { User } from '../entities/User';
import { sign } from '../helpers/token';
import { check } from '../helpers/verifyPassward';
import { getRepository } from 'typeorm';

// import { blackListedTokens } from '../middlewares/authentication';

class signinAndOutController {
// Method to login admin
static async userSignin(req: Request, res: Response): Promise<void> {

Check warning on line 11 in src/controllers/signinAndOutController.ts

View workflow job for this annotation

GitHub Actions / build-lint-test-coverage

Missing space before function parentheses

Check warning on line 11 in src/controllers/signinAndOutController.ts

View workflow job for this annotation

GitHub Actions / build-lint-test-coverage

Missing space before function parentheses
try {
const { email, password } = req.body;

if (!email || !password) {
res.status(400).json({ Message: 'Email and password are required' });
return;
}
const userRepository = getRepository(User);

const user = await userRepository.findOneBy({ email: email });

if (!user) {
res.status(401).json({ Message: 'Invalid email' });
return;
}

const isPasswordCorrect = check(user.password, password);
if (!isPasswordCorrect) {
res.status(401).json({ Message: 'Invalid password' });
return;
}

const accessToken = sign({
id: user.id,
email: user.email,
role: user.userType,
});

const userObject: any = {
accessToken: accessToken,
};
if (process.env.NODE_ENV === 'production') {
res.cookie('accessToken', accessToken, { httpOnly: true, sameSite: 'none', secure: true });
} else {
res.cookie('accessToken', accessToken, { httpOnly: true, sameSite: 'lax' });
}

res.status(200).json({ Message: 'signed in successfully', userObject });
} catch (error) {
console.error('Error signing in a user:', error);
res.status(500).json({ error: 'Sorry, Something went wrong' });
}
}
}

export default signinAndOutController;
15 changes: 15 additions & 0 deletions src/helpers/token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import jwt from 'jsonwebtoken';
import dotenv from 'dotenv';

dotenv.config();

const jwtSecretKey = process.env.JWT_SECRETKEY;

if (!jwtSecretKey) {
throw new Error('JWT_SECRETKEY is not defined in the environment variables.');
}

export const sign = (payload: string | object | Buffer): string =>
jwt.sign(payload, jwtSecretKey, { expiresIn: '48h' });

export const verify = (token: string): string | object => jwt.verify(token, jwtSecretKey);
14 changes: 14 additions & 0 deletions src/helpers/verifyPassward.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import bcrypt from 'bcrypt';
import dotenv from 'dotenv';

dotenv.config();

const jwtSecretKey = process.env.JWT_SECRETKEY;

if (!jwtSecretKey) {
throw new Error('JWT_SECRETKEY is not defined in the environment variables.');
}

export const check = (hashedPassword: string, password: string): boolean => {
return bcrypt.compareSync(password, hashedPassword);
};
5 changes: 3 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import dotenv from 'dotenv';
import router from './routes';
import { addDocumentation } from './startups/docs';
import 'reflect-metadata';

import cookieParser from 'cookie-parser';

import { CustomError, errorHandler } from './middlewares/errorHandler';
import morgan from 'morgan';
Expand All @@ -14,6 +14,7 @@ dotenv.config();
export const app = express();
const port = process.env.PORT || 8000;
app.use(express.json());
app.use(cookieParser());

app.use(cors({ origin: '*' }));
app.use(router);
Expand All @@ -34,4 +35,4 @@ app.use(morgan(morganFormat));

export const server = app.listen(port, () => {
console.log(`[server]: Server is running at http://localhost:${port}`);
});
});
8 changes: 5 additions & 3 deletions src/routes/UserRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Router } from 'express';
import { Router } from 'express';
import { UserController } from '../controllers/index';

import { signinAndOutController } from '../controllers/index';

const { registerUser } = UserController;
const { userSignin } = signinAndOutController;

const router = Router();

router.post('/register', registerUser);
router.post('/signin', userSignin);

export default router;
export default router;

0 comments on commit f8ffab6

Please sign in to comment.