Skip to content

Commit

Permalink
Merge pull request #2214 from Real-Dev-Squad/develop
Browse files Browse the repository at this point in the history
Dev to Main Sync
  • Loading branch information
iamitprakash authored Oct 19, 2024
2 parents 46f5d4f + c5a70f3 commit a74136b
Show file tree
Hide file tree
Showing 24 changed files with 709 additions and 14 deletions.
10 changes: 10 additions & 0 deletions config/custom-environment-variables.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@ module.exports = {
},
},

emailServiceConfig: {
email: "RDS_EMAIL",
password: "RDS_EMAIL_PASSWORD",
host: "SMTP_HOST",
port: {
__name: "SMTP_PORT",
__format: "number",
},
},

userToken: {
cookieName: "COOKIE_NAME",
ttl: {
Expand Down
7 changes: 7 additions & 0 deletions config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ module.exports = {
clientSecret: "<clientSecret>",
},

emailServiceConfig: {
email: "<RDS_EMAIL>",
password: "<EMAIL PASSWORD GENERATED AFTER 2FA>",
host: "<smtp host>",
port: "<number>",
},

firestore: `{
"type": "service_account",
"project_id": "<project-name>",
Expand Down
2 changes: 2 additions & 0 deletions constants/subscription-validator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
export const phoneNumberRegex = /^[+]{1}(?:[0-9\-\\(\\)\\/.]\s?){6,15}[0-9]{1}$/;
74 changes: 74 additions & 0 deletions controllers/subscription.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { CustomRequest, CustomResponse } from "../types/global";
const { addOrUpdate } = require("../models/users");
const { INTERNAL_SERVER_ERROR } = require("../constants/errorMessages");
const nodemailer = require("nodemailer");
const config = require("config");
const emailServiceConfig = config.get("emailServiceConfig");

export const subscribe = async (req: CustomRequest, res: CustomResponse) => {
const { email } = req.body;
const phoneNumber = req.body.phoneNumber || null;
const userId = req.userData.id;
const data = { email, isSubscribed: true, phoneNumber };
const userAlreadySubscribed = req.userData.isSubscribed;
try {
if (userAlreadySubscribed) {
return res.boom.badRequest("User already subscribed");
}
await addOrUpdate(data, userId);
return res.status(201).json("User subscribed successfully");
} catch (error) {
logger.error(`Error occurred while subscribing: ${error.message}`);
return res.boom.badImplementation(INTERNAL_SERVER_ERROR);
}
};

export const unsubscribe = async (req: CustomRequest, res: CustomResponse) => {
const userId = req.userData.id;
const userAlreadySubscribed = req.userData.isSubscribed;
try {
if (!userAlreadySubscribed) {
return res.boom.badRequest("User is already unsubscribed");
}
await addOrUpdate(
{
isSubscribed: false,
},
userId
);
return res.status(200).json("User unsubscribed successfully");
} catch (error) {
logger.error(`Error occurred while unsubscribing: ${error.message}`);
return res.boom.badImplementation(INTERNAL_SERVER_ERROR);
}
};

// TODO: currently we are sending test email to a user only (i.e., Tejas sir as decided)
// later we need to make service which send email to all subscribed user
export const sendEmail = async (req: CustomRequest, res: CustomResponse) => {
try {
const transporter = nodemailer.createTransport({
host: emailServiceConfig.host,
port: emailServiceConfig.port,
secure: false,

auth: {
user: emailServiceConfig.email,
pass: emailServiceConfig.password,
},
});

const info = await transporter.sendMail({
from: `"Real Dev Squad" <${emailServiceConfig.email}>`,
to: "[email protected]",
subject: "Hello local, Testing in progress.",
text: "working for notification feature",
html: "<b>Hello world!</b>",
});

return res.send({ message: "Email sent successfully", info });
} catch (error) {
logger.error("Error occurred while sending email:", error.message);
return res.boom.badImplementation(INTERNAL_SERVER_ERROR);
}
};
21 changes: 21 additions & 0 deletions controllers/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,26 @@ const getUsers = async (req, res) => {
});
}

const profile = req.query.profile === "true";

if (profile) {
if (dev) {
if (!req.userData.id) {
return res.boom.badRequest("User ID not provided.");
}

try {
const result = await dataAccess.retrieveUsers({ id: req.userData.id });
return res.send(result.user);
} catch (error) {
logger.error(`Error while fetching user: ${error}`);
return res.boom.serverUnavailable(INTERNAL_SERVER_ERROR);
}
} else {
return res.boom.badRequest("Route not found");
}
}

if (!transformedQuery?.days && transformedQuery?.filterBy === "unmerged_prs") {
return res.boom.badRequest(`Days is required for filterBy ${transformedQuery?.filterBy}`);
}
Expand Down Expand Up @@ -393,6 +413,7 @@ const getSelfDetails = async (req, res) => {
* @param req.body {Object} - User object
* @param res {Object} - Express response object
*/

const updateSelf = async (req, res) => {
try {
const { id: userId, roles: userRoles, discordId } = req.userData;
Expand Down
10 changes: 10 additions & 0 deletions middlewares/authenticateProfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const authenticateProfile = (authenticate) => {
return async (req, res, next) => {
if (req.query.profile === "true") {
return await authenticate(req, res, next);
}
return next();
};
};

module.exports = authenticateProfile;
15 changes: 15 additions & 0 deletions middlewares/devFlag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { NextFunction } from "express";
import { CustomRequest, CustomResponse } from "../types/global";

export const devFlagMiddleware = (req: CustomRequest, res: CustomResponse, next: NextFunction) => {
try {
const dev = req.query.dev === "true";
if (!dev) {
return res.boom.notFound("Route not found");
}
next();
} catch (err) {
logger.error("Error occurred in devFlagMiddleware:", err.message);
next(err);
}
};
23 changes: 23 additions & 0 deletions middlewares/validators/subscription.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { NextFunction } from "express";
import { CustomRequest, CustomResponse } from "../../types/global";
import { emailRegex, phoneNumberRegex } from "../../constants/subscription-validator";
import Joi from 'joi';

export const validateSubscribe = (req: CustomRequest, res: CustomResponse, next: NextFunction) => {

if(req.body.email){
req.body.email = req.body.email.trim();
}
if (req.body.phoneNumber) {
req.body.phoneNumber = req.body.phoneNumber.trim();
}
const subscribeSchema = Joi.object({
phoneNumber: Joi.string().allow('').optional().regex(phoneNumberRegex),
email: Joi.string().required().regex(emailRegex)
});
const { error } = subscribeSchema.validate(req.body);
if (error) {
return res.status(400).json({ error: error.details[0].message });
}
next();
};
1 change: 1 addition & 0 deletions middlewares/validators/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ async function getUsers(req, res, next) {
}),
query: joi.string().optional(),
q: joi.string().optional(),
profile: joi.string().valid("true").optional(),
filterBy: joi.string().optional(),
days: joi.string().optional(),
dev: joi.string().optional(),
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"tdd:watch": "sh scripts/tests/tdd.sh"
},
"dependencies": {
"@types/nodemailer": "^6.4.15",
"axios": "1.7.2",
"cloudinary": "2.0.3",
"config": "3.3.7",
Expand All @@ -34,6 +35,8 @@
"morgan": "1.10.0",
"multer": "1.4.5-lts.1",
"newrelic": "11.19.0",
"nodemailer": "^6.9.15",
"nodemailer-mock": "^2.0.6",
"passport": "0.7.0",
"passport-github2": "0.1.12",
"rate-limiter-flexible": "5.0.3",
Expand Down
2 changes: 2 additions & 0 deletions routes/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import express from "express";
const app = express.Router();
import { devFlagMiddleware } from "../middlewares/devFlag";

app.use("/answers", require("./answers"));
app.use("/auctions", require("./auctions"));
Expand Down Expand Up @@ -39,4 +40,5 @@ app.use("/v1/notifications", require("./notify"));
app.use("/goals", require("./goals"));
app.use("/invites", require("./invites"));
app.use("/requests", require("./requests"));
app.use("/subscription", devFlagMiddleware, require("./subscription"));
module.exports = app;
12 changes: 12 additions & 0 deletions routes/subscription.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import express from "express";
import authenticate from "../middlewares/authenticate";
import { subscribe, unsubscribe, sendEmail } from "../controllers/subscription";
import { validateSubscribe } from "../middlewares/validators/subscription";
const authorizeRoles = require("../middlewares/authorizeRoles");
const router = express.Router();
const { SUPERUSER } = require("../constants/roles");

router.post("/", authenticate, validateSubscribe, subscribe);
router.patch("/", authenticate, unsubscribe);
router.get("/notify", authenticate, authorizeRoles([SUPERUSER]), sendEmail);
module.exports = router;
3 changes: 2 additions & 1 deletion routes/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ const checkIsVerifiedDiscord = require("../middlewares/verifydiscord");
const { authorizeAndAuthenticate } = require("../middlewares/authorizeUsersAndService");
const ROLES = require("../constants/roles");
const { Services } = require("../constants/bot");
const authenticateProfile = require("../middlewares/authenticateProfile");

router.post("/", authorizeAndAuthenticate([ROLES.SUPERUSER], [Services.CRON_JOB_HANDLER]), users.markUnverified);
router.post("/update-in-discord", authenticate, authorizeRoles([SUPERUSER]), users.setInDiscordScript);
router.post("/verify", authenticate, users.verifyUser);
router.get("/userId/:userId", users.getUserById);
router.patch("/self", authenticate, userValidator.updateUser, users.updateSelf);
router.get("/", userValidator.getUsers, users.getUsers);
router.get("/", authenticateProfile(authenticate), userValidator.getUsers, users.getUsers);
router.get("/self", authenticate, users.getSelfDetails);
router.get("/isDeveloper", authenticate, users.isDeveloper);
router.get("/isUsernameAvailable/:username", authenticate, users.getUsernameAvailabilty);
Expand Down
7 changes: 7 additions & 0 deletions test/config/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ module.exports = {
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-hqc2v%40dev-rds.iam.gserviceaccount.com"
}`,

emailServiceConfig: {
email: "<RDS_EMAIL>",
password: "<EMAIL PASSWORD GENERATED AFTER 2FA>",
host: "<smtp host>",
port: "<number>",
},
services: {
rdsApi: {
baseUrl: `http://localhost:${port}`,
Expand Down
7 changes: 7 additions & 0 deletions test/fixtures/subscription/subscription.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const subscribedMessage = "User subscribed successfully";
export const unSubscribedMessage = "User unsubscribed successfully";
export const subscriptionData = {
phoneNumber: "+911234567890",
email: "[email protected]",
};

Loading

0 comments on commit a74136b

Please sign in to comment.