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 6ea1c78
Show file tree
Hide file tree
Showing 5 changed files with 265 additions and 2 deletions.
97 changes: 97 additions & 0 deletions src/__test__/subscribe.Test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import request from 'supertest';
import app from '../app';
import { afterAllHook, beforeAllHook } from './testSetup';
import dbConnection from '../database';
import Subscription from '../database/models/subscribe';

const subscribeRepository = dbConnection.getRepository(Subscription);

beforeAll(async () => {
await beforeAllHook();
});

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

describe('POST /api/v1/subscribe', () => {
beforeEach(async () => {
// Clear the table before each test
await subscribeRepository.clear();
});

it('should subscribe successfully with a valid email', async () => {
const response = await request(app)
.post('/api/v1/subscribe')
.send({ email: 'test@example.com' });

expect(response.status).toBe(201);
expect(response.body.message).toBe('Subscribed successfully');
expect(response.body.subscription.email).toBe('test@example.com');

const subscription = await subscribeRepository.findOne({
where: { email: 'test@example.com' },
});
expect(subscription).toBeDefined();
});

it('should return 400 if the email is already subscribed', async () => {
const subscription = new Subscription();
subscription.email = 'test@example.com';
await subscribeRepository.save(subscription);

const response = await request(app)
.post('/api/v1/subscribe')
.send({ email: 'test@example.com' });

expect(response.status).toBe(400);
expect(response.body.message).toBe('Email is already subscribed');
});

it('should return 400 for an invalid email format', async () => {
const response = await request(app)
.post('/api/v1/subscribe')
.send({ email: 'invalid-email' });

expect(response.status).toBe(400);
expect(response.body.errors[0].msg).toBe('Email is not valid');
});
});

describe('DELETE /api/v1/subscribe/delete/:id', () => {
beforeEach(async () => {
// Clear the table before each test
await subscribeRepository.clear();
});

it('should remove a subscription successfully', async () => {
const subscription = new Subscription();
subscription.email = 'test@example.com';
await subscribeRepository.save(subscription);

const response = await request(app)
.delete(`/api/v1/subscribe/delete/${subscription.id}`)
.send();

expect(response.status).toBe(200);
expect(response.body.message).toBe('Subscription removed successfully');
});

it('should return 404 if the subscription does not exist', async () => {
const response = await request(app)
.delete('/api/v1/subscribe/delete/450')
.send();

expect(response.status).toBe(404);
expect(response.body.message).toBe('Subscription not found');
});

it('should return 400 for invalid ID', async () => {
const response = await request(app)
.delete('/api/v1/subscribe/delete/noid')
.send();

expect(response.status).toBe(400);
expect(response.body.message).toBeUndefined();
});
});
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: test@gmail.com
* 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: test@gmail.com
*/

/**
* @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 6ea1c78

Please sign in to comment.