Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev to Main Sync #2214

Merged
merged 4 commits into from
Oct 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
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 Expand Up @@ -59,7 +66,7 @@
},

cors: {
allowedOrigins: /(https:\/\/([a-zA-Z0-9-_]+\.)?realdevsquad\.com$)/, // Allow realdevsquad.com, *.realdevsquad.com

Check warning on line 69 in config/default.js

View workflow job for this annotation

GitHub Actions / build (20.11.x)

Unsafe Regular Expression
},

userToken: {
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
Loading