Skip to content

Commit

Permalink
mend
Browse files Browse the repository at this point in the history
  • Loading branch information
13XAVI committed Jun 25, 2024
2 parents 3578d42 + 01fe04c commit b48a5e6
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 6 deletions.
7 changes: 7 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

97 changes: 97 additions & 0 deletions src/__test__/subscription.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;
}
8 changes: 4 additions & 4 deletions src/emails/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import axios from 'axios';
import handlebars from 'handlebars';
import fs from 'fs';
type EmailType = 'confirm' | 'reset';
type EmailType = 'confirm' | 'reset' | 'subscription';
type Data = {
name: string;
link: string;
name?: string;
link?: string;
};
/**
* Sends an email of the specified type to the recipient using the provided data.
Expand All @@ -15,7 +15,7 @@ type Data = {
* @returns A Promise that resolves to the response from the email service.
* @throws An error if there is an issue sending the email.
*/
async function sendEmail(emailType: EmailType, recipient: string, data: Data) {
async function sendEmail(emailType: EmailType, recipient: string, data?: Data) {
const templatePath = `./src/emails/templates/${emailType}.html`;
try {
// Read the Handlebars template file
Expand Down
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 b48a5e6

Please sign in to comment.