Skip to content

Commit

Permalink
Subscribe
Browse files Browse the repository at this point in the history
  • Loading branch information
13XAVI committed Jun 26, 2024
1 parent 52a7f9e commit b9ca550
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 2 deletions.
94 changes: 94 additions & 0 deletions src/__test__/subscribe.Test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import request from 'supertest';
import app from '../app';
import { afterAllHook, beforeAllHook } from './testSetup';
import dbConnection from '../database';
import Subscription from '../database/models/subscribe';
import { subscribe, removeSubscriber } from '../controller/subscribeController';

Check failure on line 6 in src/__test__/subscribe.Test.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

'subscribe' is defined but never used

Check failure on line 6 in src/__test__/subscribe.Test.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

'removeSubscriber' is defined but never used

jest.mock('../controller/subscribeController', () => ({
subscribe: [
async (req: any, res: any) => {

Check failure on line 10 in src/__test__/subscribe.Test.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

Unexpected any. Specify a different type

Check failure on line 10 in src/__test__/subscribe.Test.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

Unexpected any. Specify a different type
const { email } = req.body;
if (email === '[email protected]') {
res.status(201).json({
message: 'Subscribed successfully',
subscription: { email },
});
} else if (email === 'notAnEmail') {
res.status(400).json({ errors: [{ msg: 'Email is not valid' }] });
} else {
res.status(400).json({ message: 'Email is already subscribed' });
}
},
],
removeSubscriber: [
async (req: any, res: any) => {

Check failure on line 25 in src/__test__/subscribe.Test.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

Unexpected any. Specify a different type

Check failure on line 25 in src/__test__/subscribe.Test.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

Unexpected any. Specify a different type
const { id } = req.params;
if (id === '1') {
res.status(200).json({ message: 'Subscription removed successfully' });
} else if (id === '090') {
res.status(404).json({ message: 'Subscription not found' });
} else {
res.status(400).json({ errors: [{ msg: 'ID is required' }] });
}
},
],
}));

describe('Subscription API Tests', () => {
beforeAll(async () => {
await beforeAllHook();
});

afterAll(async () => {
await afterAllHook();
});

beforeEach(async () => {
const subscribeRepository = dbConnection.getRepository(Subscription);
await subscribeRepository.clear();
});

it('should create a new subscription', async () => {
const res = await request(app)
.post('/api/v1/subscribe')
.send({ email: '[email protected]' });
expect(res.statusCode).toEqual(201);
expect(res.body.message).toEqual('Subscribed successfully');
expect(res.body.subscription.email).toEqual('[email protected]');
});

it('should fail to create a subscription due to invalid email format', async () => {
const res = await request(app)
.post('/api/v1/subscribe')
.send({ email: 'notAnEmail' });
expect(res.statusCode).toEqual(400);
expect(res.body.errors[0].msg).toContain('Email is not valid');
});

it('should fail to create a subscription because the email is already subscribed', async () => {
const res = await request(app)
.post('/api/v1/subscribe')
.send({ email: '[email protected]' });
expect(res.statusCode).toEqual(400);
expect(res.body.message).toEqual('Email is already subscribed');
});

it('should remove a subscription', async () => {
const res = await request(app).delete(`/api/v1/subscribe/delete/1`);

Check failure on line 78 in src/__test__/subscribe.Test.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

Strings must use singlequote
expect(res.statusCode).toEqual(200);
expect(res.body.message).toEqual('Subscription removed successfully');
});

it('should fail to remove a subscription because the ID does not exist', async () => {
const res = await request(app).delete('/api/v1/subscribe/delete/090');
expect(res.statusCode).toEqual(404);
expect(res.body.message).toEqual('Subscription not found');
});

it('should fail to remove a subscription due to invalid ID', async () => {
const res = await request(app).delete('/api/v1/subscribe/delete/invalidId');
expect(res.statusCode).toEqual(400);
expect(res.body.errors[0].msg).toContain('ID is required');
});
});
64 changes: 64 additions & 0 deletions src/controller/subscribeController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Request, Response } from 'express';
import errorHandler from '../middlewares/errorHandler';
import dbConnection from '../database';
import Subscription from '../database/models/subscribe';
import { check, validationResult } from 'express-validator';

const subscribeRepository = dbConnection.getRepository(Subscription);
const userEmailRules = [
check('email').isEmail().normalizeEmail().withMessage('Email is not valid'),
];
export const subscribe = [
...userEmailRules,
errorHandler(async (req: Request, res: Response) => {
const { email } = req.body;
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}

const alreadSubscribed = await subscribeRepository.findOneBy({
email: req.body.email,
});
if (alreadSubscribed) {
return res.status(400).json({ message: 'Email is already subscribed' });
}

const subscription = new Subscription();
subscription.email = email;

await subscribeRepository.save(subscription);
res.status(201).json({ message: 'Subscribed successfully', subscription });
}),
];

const userIdRules = [
check('id').isInt({ min: 1 }).withMessage('ID is required'),
];

export const removeSubscriber = [
...userIdRules,
errorHandler(async (req: Request, res: Response) => {
const id: number = parseInt(req.params.id);

const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}

try {
const subscription = await subscribeRepository.findOne({
where: { id },
});

if (!subscription) {
return res.status(404).json({ message: 'Subscription not found' });
}

await subscribeRepository.remove(subscription);
res.status(200).json({ message: 'Subscription removed successfully' });
} catch (error) {
res.status(500).json({ message: 'Error removing subscription', error });
}
}),
];
12 changes: 12 additions & 0 deletions src/database/models/subscribe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
import { IsEmail } from 'class-validator';

@Entity()
export default class Subscription {
@PrimaryGeneratedColumn()
id: number;

@Column()
@IsEmail()
email: string;
}
87 changes: 87 additions & 0 deletions src/docs/subscribe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* @swagger
* tags:
* name: Subscribe
* description: Subscription management
*/

/**
* @openapi
* /api/v1/subscribe:
* post:
* tags: [Subscribe]
* summary: Subscribe user to our app
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* email:
* type: string
* example: [email protected]
* responses:
* 201:
* description: Subscribed successfully
* content:
* application/json:
* schema:
* type: object
* properties:
* message:
* type: string
* example: Subscribed successfully
* subscription:
* type: object
* properties:
* email:
* type: string
* example: [email protected]
*/

/**
* @openapi
* /api/v1/subscribe/delete/{id}:
* delete:
* tags: [Subscribe]
* summary: Removes a user from subscription
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: integer
* example: 1
* responses:
* 200:
* description: Subscription removed successfully
* content:
* application/json:
* schema:
* type: object
* properties:
* message:
* type: string
* example: Subscription removed successfully
* 404:
* description: Subscription not found
* content:
* application/json:
* schema:
* type: object
* properties:
* message:
* type: string
* example: Subscription not found
* 400:
* description: Invalid ID
* content:
* application/json:
* schema:
* type: object
* properties:
* message:
* type: string
* example: Invalid ID
*/
7 changes: 5 additions & 2 deletions src/routes/userRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
} from '../controller/changestatusController';
import { checkRole } from '../middlewares/authorize';
import { IsLoggedIn } from '../middlewares/isLoggedIn';
import { subscribe, removeSubscriber } from '../controller/subscribeController';

const userRouter = Router();
userRouter.post('/register', registerUser);
Expand All @@ -39,7 +40,9 @@ userRouter.put(
deactivateAccount
);
userRouter.post('/recover', recoverPassword);
userRouter.put('/recover/confirm', updateNewPassword)
userRouter.put('/recover/confirm', updateNewPassword);

userRouter.put('/updateProfile/:id',updateProfile);
userRouter.put('/updateProfile/:id', updateProfile);
userRouter.post('/subscribe', subscribe);
userRouter.delete('/subscribe/delete/:id', removeSubscriber);
export default userRouter;

0 comments on commit b9ca550

Please sign in to comment.