Skip to content

Commit

Permalink
Revert "pay with momo"
Browse files Browse the repository at this point in the history
This reverts commit 7270354.
  • Loading branch information
13XAVI committed Jul 1, 2024
1 parent e8e258b commit d59f75c
Show file tree
Hide file tree
Showing 9 changed files with 241 additions and 10 deletions.
7 changes: 4 additions & 3 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
"@types/mailgun-js": "^0.22.18",
"@types/mocha": "^10.0.7",
"@types/morgan": "^1.9.9",
"@types/node": "^20.14.9",
"@types/node-cron": "^3.0.11",
"@types/node-fetch": "^2.6.11",
"@types/nodemailer": "^6.4.15",
Expand Down
33 changes: 30 additions & 3 deletions src/__test__/subscribe.Test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ describe('DELETE /api/v1/subscribe/delete/:id', () => {
await subscribeRepository.save(subscription);

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

expect(response.status).toBe(200);
Expand All @@ -79,7 +79,7 @@ describe('DELETE /api/v1/subscribe/delete/:id', () => {

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

expect(response.status).toBe(404);
Expand All @@ -88,10 +88,37 @@ describe('DELETE /api/v1/subscribe/delete/:id', () => {

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

expect(response.status).toBe(400);
expect(response.body.message).toBeUndefined();
});
});

describe('GET /api/v1/subscribe/getAll', () => {
beforeEach(async () => {
await subscribeRepository.clear();
});

it('should return all subscriptions', async () => {
const subscription1 = new Subscription();
subscription1.email = '[email protected]';
await subscribeRepository.save(subscription1);

const subscription2 = new Subscription();
subscription2.email = '[email protected]';
await subscribeRepository.save(subscription2);

const response = await request(app).get('/api/v1/subscribe/getAll').send();

expect(response.status).toBe(200);
expect(response.body.subscription).toHaveLength(2);
expect(response.body.subscription).toEqual(
expect.arrayContaining([
expect.objectContaining({ email: '[email protected]' }),
expect.objectContaining({ email: '[email protected]' }),
])
);
});
});
31 changes: 31 additions & 0 deletions src/controller/subscribeController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import errorHandler from '../middlewares/errorHandler';
import dbConnection from '../database';
import Subscription from '../database/models/subscribe';
import { check, validationResult } from 'express-validator';
import sendEmail from '../emails';

const subscribeRepository = dbConnection.getRepository(Subscription);
const userEmailRules = [
Expand All @@ -28,6 +29,11 @@ export const subscribe = [
subscription.email = email;

await subscribeRepository.save(subscription);
const unsubscribeLink = process.env.unsubscribe;
await sendEmail('subscribe', email, {
name: email,
link: `${unsubscribeLink}/${subscription.id}`,
});
res.status(201).json({ message: 'Subscribed successfully', subscription });
}),
];
Expand Down Expand Up @@ -62,3 +68,28 @@ export const removeSubscriber = [
}
}),
];

export const getAllSubscriber = [
errorHandler(async (req: Request, res: Response) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}

try {
const subscription = await subscribeRepository.find({
select: {
email: true,
},
});

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

res.status(200).json({ subscription });
} catch (error) {
res.status(500).json({ message: 'Internal error', error });
}
}),
];
35 changes: 34 additions & 1 deletion src/docs/subscribe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
/**
* @openapi
* /api/v1/subscribe/delete/{id}:
* delete:
* get:
* tags: [Subscribe]
* summary: Removes a user from subscription
* parameters:
Expand Down Expand Up @@ -85,3 +85,36 @@
* type: string
* example: Invalid ID
*/

/**
* @openapi
* /api/v1/subscribe/getAll:
* get:
* tags: [Subscribe]
* summary: Retrieve all subscribers
* description: Get a list of all subscribers in the system.
* responses:
* 200:
* description: A list of subscribers
* content:
* application/json:
* schema:
* type: array
* items:
* type: object
* properties:
* id:
* type: integer
* example: 1
* email:
* type: string
* example: [email protected]
* createdAt:
* type: string
* format: date-time
* example: 2024-06-29T12:34:56Z
* updatedAt:
* type: string
* format: date-time
* example: 2024-06-29T12:34:56Z
*/
2 changes: 1 addition & 1 deletion src/emails/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import axios from 'axios';
import handlebars from 'handlebars';
import fs from 'fs';
type EmailType = 'confirm' | 'reset';
type EmailType = 'confirm' | 'reset' | 'subscribe';
type Data = {
name: string;
link: string;
Expand Down
62 changes: 62 additions & 0 deletions src/emails/subscribe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import axios from 'axios';
import handlebars from 'handlebars';
import fs from 'fs';
import dotenv from 'dotenv';
dotenv.config();
type EmailType = 'subscribe' | 'unsubscribe';
type Data = {
name: string;
link: string;
};
/**
* Sends an email of the specified type to the recipient using the provided data.
*
* @param emailType - The type of email to send. Must be either "confirm" or "reset".
* @param recipient - The email address of the recipient.
* @param data - The data to be used for generating the email content. A name and link are required.
* @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) {
const templatePath = `./src/emails/templates/${emailType}.html`;
try {
// Read the Handlebars template file
const templateFile = fs.readFileSync(templatePath, 'utf-8');

// Compile the template
const template = handlebars.compile(templateFile);

// Generate the HTML content using the template and data
const html = template(data);

// Send the Email

const domain = process.env.MAILGUN_DOMAIN;
const key = process.env.MAILGUN_TOKEN as string;
const body = {
from: `Dynamites Account Team <info@${domain}>`,
to: [recipient],
subject: 'Verification Email',
html: html,
};
const mailgunResponse = await axios.post(
`https://api.mailgun.net/v3/${domain}/messages`,
body,
{
auth: {
username: 'api',
password: key,
},
headers: {
'Content-Type': 'multipart/form-data',
},
}
);

return mailgunResponse;
} catch (error) {
throw new Error(`Error sending email: ${error}`);
}
}

export default sendEmail;
71 changes: 71 additions & 0 deletions src/emails/templates/subscribe.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Welcome to Our Newsletter</title>
<style>
body {
font-family: Arial, sans-serif;
line-height: 1.6;
background-color: #f4f4f4;
color: #333;
padding: 20px;
}
.container {
max-width: 600px;
margin: 0 auto;
background: #fff;
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.header {
text-align: center;
padding-bottom: 20px;
}
.content {
text-align: center;
}
.footer {
text-align: center;
margin-top: 20px;
font-size: 12px;
color: #777;
}
.link {
color: #4c51bf;
text-decoration: none;
}

.link:hover {
color: #434190;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Welcome to Our Newsletter!</h1>
</div>
<div class="content">
<p>Hi there,</p>
<p>
Thank you for subscribing to our newsletter. We're excited to have you
with us!
</p>
<p>
You'll receive regular updates on our latest content, news, and
special offers.
</p>
</div>
<div class="footer">
<p>&copy; 2024 Dynamites Ecommerce. All rights reserved.</p>
<p>
If you didn't subscribe to this newsletter, please
<a href="{{link}}" class="link">unsubscribe</a>
</p>
</div>
</div>
</body>
</html>
9 changes: 7 additions & 2 deletions src/routes/userRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ import {
} from '../controller/changestatusController';
import { checkRole } from '../middlewares/authorize';
import { IsLoggedIn } from '../middlewares/isLoggedIn';
import { subscribe, removeSubscriber } from '../controller/subscribeController';
import {
subscribe,
removeSubscriber,
getAllSubscriber,
} from '../controller/subscribeController';

const userRouter = Router();
userRouter.post('/register', registerUser);
Expand Down Expand Up @@ -46,5 +50,6 @@ userRouter.put('/recover/confirm', updateNewPassword);

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

0 comments on commit d59f75c

Please sign in to comment.