Skip to content

Commit a74136b

Browse files
authored
Merge pull request #2214 from Real-Dev-Squad/develop
Dev to Main Sync
2 parents 46f5d4f + c5a70f3 commit a74136b

24 files changed

+709
-14
lines changed

config/custom-environment-variables.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@ module.exports = {
5555
},
5656
},
5757

58+
emailServiceConfig: {
59+
email: "RDS_EMAIL",
60+
password: "RDS_EMAIL_PASSWORD",
61+
host: "SMTP_HOST",
62+
port: {
63+
__name: "SMTP_PORT",
64+
__format: "number",
65+
},
66+
},
67+
5868
userToken: {
5969
cookieName: "COOKIE_NAME",
6070
ttl: {

config/default.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ module.exports = {
2525
clientSecret: "<clientSecret>",
2626
},
2727

28+
emailServiceConfig: {
29+
email: "<RDS_EMAIL>",
30+
password: "<EMAIL PASSWORD GENERATED AFTER 2FA>",
31+
host: "<smtp host>",
32+
port: "<number>",
33+
},
34+
2835
firestore: `{
2936
"type": "service_account",
3037
"project_id": "<project-name>",
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
2+
export const phoneNumberRegex = /^[+]{1}(?:[0-9\-\\(\\)\\/.]\s?){6,15}[0-9]{1}$/;

controllers/subscription.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { CustomRequest, CustomResponse } from "../types/global";
2+
const { addOrUpdate } = require("../models/users");
3+
const { INTERNAL_SERVER_ERROR } = require("../constants/errorMessages");
4+
const nodemailer = require("nodemailer");
5+
const config = require("config");
6+
const emailServiceConfig = config.get("emailServiceConfig");
7+
8+
export const subscribe = async (req: CustomRequest, res: CustomResponse) => {
9+
const { email } = req.body;
10+
const phoneNumber = req.body.phoneNumber || null;
11+
const userId = req.userData.id;
12+
const data = { email, isSubscribed: true, phoneNumber };
13+
const userAlreadySubscribed = req.userData.isSubscribed;
14+
try {
15+
if (userAlreadySubscribed) {
16+
return res.boom.badRequest("User already subscribed");
17+
}
18+
await addOrUpdate(data, userId);
19+
return res.status(201).json("User subscribed successfully");
20+
} catch (error) {
21+
logger.error(`Error occurred while subscribing: ${error.message}`);
22+
return res.boom.badImplementation(INTERNAL_SERVER_ERROR);
23+
}
24+
};
25+
26+
export const unsubscribe = async (req: CustomRequest, res: CustomResponse) => {
27+
const userId = req.userData.id;
28+
const userAlreadySubscribed = req.userData.isSubscribed;
29+
try {
30+
if (!userAlreadySubscribed) {
31+
return res.boom.badRequest("User is already unsubscribed");
32+
}
33+
await addOrUpdate(
34+
{
35+
isSubscribed: false,
36+
},
37+
userId
38+
);
39+
return res.status(200).json("User unsubscribed successfully");
40+
} catch (error) {
41+
logger.error(`Error occurred while unsubscribing: ${error.message}`);
42+
return res.boom.badImplementation(INTERNAL_SERVER_ERROR);
43+
}
44+
};
45+
46+
// TODO: currently we are sending test email to a user only (i.e., Tejas sir as decided)
47+
// later we need to make service which send email to all subscribed user
48+
export const sendEmail = async (req: CustomRequest, res: CustomResponse) => {
49+
try {
50+
const transporter = nodemailer.createTransport({
51+
host: emailServiceConfig.host,
52+
port: emailServiceConfig.port,
53+
secure: false,
54+
55+
auth: {
56+
user: emailServiceConfig.email,
57+
pass: emailServiceConfig.password,
58+
},
59+
});
60+
61+
const info = await transporter.sendMail({
62+
from: `"Real Dev Squad" <${emailServiceConfig.email}>`,
63+
64+
subject: "Hello local, Testing in progress.",
65+
text: "working for notification feature",
66+
html: "<b>Hello world!</b>",
67+
});
68+
69+
return res.send({ message: "Email sent successfully", info });
70+
} catch (error) {
71+
logger.error("Error occurred while sending email:", error.message);
72+
return res.boom.badImplementation(INTERNAL_SERVER_ERROR);
73+
}
74+
};

controllers/users.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,26 @@ const getUsers = async (req, res) => {
113113
});
114114
}
115115

116+
const profile = req.query.profile === "true";
117+
118+
if (profile) {
119+
if (dev) {
120+
if (!req.userData.id) {
121+
return res.boom.badRequest("User ID not provided.");
122+
}
123+
124+
try {
125+
const result = await dataAccess.retrieveUsers({ id: req.userData.id });
126+
return res.send(result.user);
127+
} catch (error) {
128+
logger.error(`Error while fetching user: ${error}`);
129+
return res.boom.serverUnavailable(INTERNAL_SERVER_ERROR);
130+
}
131+
} else {
132+
return res.boom.badRequest("Route not found");
133+
}
134+
}
135+
116136
if (!transformedQuery?.days && transformedQuery?.filterBy === "unmerged_prs") {
117137
return res.boom.badRequest(`Days is required for filterBy ${transformedQuery?.filterBy}`);
118138
}
@@ -393,6 +413,7 @@ const getSelfDetails = async (req, res) => {
393413
* @param req.body {Object} - User object
394414
* @param res {Object} - Express response object
395415
*/
416+
396417
const updateSelf = async (req, res) => {
397418
try {
398419
const { id: userId, roles: userRoles, discordId } = req.userData;

middlewares/authenticateProfile.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const authenticateProfile = (authenticate) => {
2+
return async (req, res, next) => {
3+
if (req.query.profile === "true") {
4+
return await authenticate(req, res, next);
5+
}
6+
return next();
7+
};
8+
};
9+
10+
module.exports = authenticateProfile;

middlewares/devFlag.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { NextFunction } from "express";
2+
import { CustomRequest, CustomResponse } from "../types/global";
3+
4+
export const devFlagMiddleware = (req: CustomRequest, res: CustomResponse, next: NextFunction) => {
5+
try {
6+
const dev = req.query.dev === "true";
7+
if (!dev) {
8+
return res.boom.notFound("Route not found");
9+
}
10+
next();
11+
} catch (err) {
12+
logger.error("Error occurred in devFlagMiddleware:", err.message);
13+
next(err);
14+
}
15+
};
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { NextFunction } from "express";
2+
import { CustomRequest, CustomResponse } from "../../types/global";
3+
import { emailRegex, phoneNumberRegex } from "../../constants/subscription-validator";
4+
import Joi from 'joi';
5+
6+
export const validateSubscribe = (req: CustomRequest, res: CustomResponse, next: NextFunction) => {
7+
8+
if(req.body.email){
9+
req.body.email = req.body.email.trim();
10+
}
11+
if (req.body.phoneNumber) {
12+
req.body.phoneNumber = req.body.phoneNumber.trim();
13+
}
14+
const subscribeSchema = Joi.object({
15+
phoneNumber: Joi.string().allow('').optional().regex(phoneNumberRegex),
16+
email: Joi.string().required().regex(emailRegex)
17+
});
18+
const { error } = subscribeSchema.validate(req.body);
19+
if (error) {
20+
return res.status(400).json({ error: error.details[0].message });
21+
}
22+
next();
23+
};

middlewares/validators/user.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ async function getUsers(req, res, next) {
196196
}),
197197
query: joi.string().optional(),
198198
q: joi.string().optional(),
199+
profile: joi.string().valid("true").optional(),
199200
filterBy: joi.string().optional(),
200201
days: joi.string().optional(),
201202
dev: joi.string().optional(),

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"tdd:watch": "sh scripts/tests/tdd.sh"
1717
},
1818
"dependencies": {
19+
"@types/nodemailer": "^6.4.15",
1920
"axios": "1.7.2",
2021
"cloudinary": "2.0.3",
2122
"config": "3.3.7",
@@ -34,6 +35,8 @@
3435
"morgan": "1.10.0",
3536
"multer": "1.4.5-lts.1",
3637
"newrelic": "11.19.0",
38+
"nodemailer": "^6.9.15",
39+
"nodemailer-mock": "^2.0.6",
3740
"passport": "0.7.0",
3841
"passport-github2": "0.1.12",
3942
"rate-limiter-flexible": "5.0.3",

0 commit comments

Comments
 (0)