mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-02-21 10:18:57 -06:00
add update settings method, remove all env var references possible
This commit is contained in:
@@ -25,7 +25,7 @@ const { getTokenFromHeaders } = require("../utils/utils");
|
||||
* @param {Object} payload
|
||||
* @returns {String}
|
||||
*/
|
||||
const issueToken = async (payload, appSettings) => {
|
||||
const issueToken = (payload, appSettings) => {
|
||||
try {
|
||||
const tokenTTL = appSettings.jwtTTL ? appSettings.jwtTTL : "2h";
|
||||
return jwt.sign(payload, appSettings.jwtSecret, { expiresIn: tokenTTL });
|
||||
@@ -74,7 +74,6 @@ const registerController = async (req, res, next) => {
|
||||
|
||||
const appSettings = await req.settingsService.getSettings();
|
||||
const token = issueToken(userForToken, appSettings);
|
||||
|
||||
req.emailService
|
||||
.buildAndSendEmail(
|
||||
"welcomeEmailTemplate",
|
||||
@@ -137,7 +136,7 @@ const loginController = async (req, res, next) => {
|
||||
|
||||
// Happy path, return token
|
||||
const appSettings = req.settingsService.getSettings();
|
||||
const token = await issueToken(userWithoutPassword, appSettings);
|
||||
const token = issueToken(userWithoutPassword, appSettings);
|
||||
// reset avatar image
|
||||
userWithoutPassword.avatarImage = user.avatarImage;
|
||||
|
||||
@@ -186,7 +185,8 @@ const userEditController = async (req, res, next) => {
|
||||
// Get token from headers
|
||||
const token = getTokenFromHeaders(req.headers);
|
||||
// Get email from token
|
||||
const { email } = jwt.verify(token, process.env.JWT_SECRET);
|
||||
const { jwtSecret } = req.settingsService.getSettings();
|
||||
const { email } = jwt.verify(token, jwtSecret);
|
||||
// Add user email to body for DB operation
|
||||
req.body.email = email;
|
||||
// Get user
|
||||
@@ -236,12 +236,13 @@ const inviteController = async (req, res, next) => {
|
||||
}
|
||||
|
||||
const inviteToken = await req.db.requestInviteToken(req, res);
|
||||
const { clientHost } = req.settingsService.getSettings();
|
||||
req.emailService
|
||||
.buildAndSendEmail(
|
||||
"employeeActivationTemplate",
|
||||
{
|
||||
name: firstname,
|
||||
link: `${process.env.CLIENT_HOST}/register/${inviteToken.token}`,
|
||||
link: `${clientHost}/register/${inviteToken.token}`,
|
||||
},
|
||||
req.body.email,
|
||||
"Welcome to Uptime Monitor"
|
||||
@@ -345,7 +346,8 @@ const recoveryRequestController = async (req, res, next) => {
|
||||
const recoveryToken = await req.db.requestRecoveryToken(req, res);
|
||||
const name = user.firstName;
|
||||
const email = req.body.email;
|
||||
const url = `${process.env.CLIENT_HOST}/set-new-password/${recoveryToken.token}`;
|
||||
const { clientHost } = req.settingsService.getSettings();
|
||||
const url = `${clientHost}/set-new-password/${recoveryToken.token}`;
|
||||
|
||||
const msgId = await req.emailService.buildAndSendEmail(
|
||||
"passwordResetTemplate",
|
||||
|
||||
@@ -163,7 +163,8 @@ const updateChecksTTL = async (req, res, next) => {
|
||||
try {
|
||||
// Get user's teamId
|
||||
const token = getTokenFromHeaders(req.headers);
|
||||
const { teamId } = jwt.verify(token, process.env.JWT_SECRET);
|
||||
const { jwtSecret } = req.settingsService.getSettings();
|
||||
const { teamId } = jwt.verify(token, jwtSecret);
|
||||
const ttl = parseInt(req.body.ttl, 10) * SECONDS_PER_DAY;
|
||||
await req.db.updateChecksTTL(teamId, ttl);
|
||||
return res.status(200).json({
|
||||
|
||||
@@ -39,12 +39,13 @@ const inviteController = async (req, res, next) => {
|
||||
}
|
||||
|
||||
const inviteToken = await req.db.requestInviteToken({ ...req.body });
|
||||
const { clientHost } = req.settingsService.getSettings();
|
||||
req.emailService
|
||||
.buildAndSendEmail(
|
||||
"employeeActivationTemplate",
|
||||
{
|
||||
name: firstname,
|
||||
link: `${process.env.CLIENT_HOST}/register/${inviteToken.token}`,
|
||||
link: `${clientHost}/register/${inviteToken.token}`,
|
||||
},
|
||||
req.body.email,
|
||||
"Welcome to Uptime Monitor"
|
||||
|
||||
@@ -345,7 +345,8 @@ const deleteMonitor = async (req, res, next) => {
|
||||
const deleteAllMonitors = async (req, res) => {
|
||||
try {
|
||||
const token = getTokenFromHeaders(req.headers);
|
||||
const { teamId } = jwt.verify(token, process.env.JWT_SECRET);
|
||||
const { jwtSecret } = req.settingsService.getSettings();
|
||||
const { teamId } = jwt.verify(token, jwtSecret);
|
||||
const { monitors, deletedCount } = await req.db.deleteAllMonitors(teamId);
|
||||
await monitors.forEach(async (monitor) => {
|
||||
await req.jobQueue.deleteJob(monitor);
|
||||
@@ -460,7 +461,9 @@ const pauseMonitor = async (req, res, next) => {
|
||||
const addDemoMonitors = async (req, res, next) => {
|
||||
try {
|
||||
const token = getTokenFromHeaders(req.headers);
|
||||
const { _id, teamId } = jwt.verify(token, process.env.JWT_SECRET);
|
||||
const { jwtSecret } = req.settingsService.getSettings();
|
||||
|
||||
const { _id, teamId } = jwt.verify(token, jwtSecret);
|
||||
const demoMonitors = await req.db.addDemoMonitors(_id, teamId);
|
||||
await demoMonitors.forEach(async (monitor) => {
|
||||
await req.jobQueue.addJob(monitor._id, monitor);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const { successMessages } = require("../utils/messages");
|
||||
const SERVICE_NAME = "SettingsController";
|
||||
const { updateAppSettingsBodyValidation } = require("../validation/joi");
|
||||
|
||||
const getAppSettings = async (req, res, next) => {
|
||||
try {
|
||||
@@ -12,9 +13,37 @@ const getAppSettings = async (req, res, next) => {
|
||||
} catch (error) {
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined ? (error.method = "getAppSettings") : null;
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
const updateAppSettings = async (req, res, next) => {
|
||||
try {
|
||||
await updateAppSettingsBodyValidation.validateAsync(req.body);
|
||||
} catch (error) {
|
||||
error.status = 422;
|
||||
error.service = SERVICE_NAME;
|
||||
error.message =
|
||||
error.details?.[0]?.message || error.message || "Validation Error";
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const settings = await req.db.updateAppSettings(req.body);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.UPDATE_APP_SETTINGS,
|
||||
data: settings,
|
||||
});
|
||||
} catch (error) {
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined ? (error.method = "updateAppSettings") : null;
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getAppSettings,
|
||||
updateAppSettings,
|
||||
};
|
||||
|
||||
@@ -137,7 +137,10 @@ const {
|
||||
//****************************************
|
||||
// AppSettings
|
||||
//****************************************
|
||||
const { getAppSettings } = require("./modules/settingsModule");
|
||||
const {
|
||||
getAppSettings,
|
||||
updateAppSettings,
|
||||
} = require("./modules/settingsModule");
|
||||
|
||||
module.exports = {
|
||||
connect,
|
||||
@@ -187,4 +190,5 @@ module.exports = {
|
||||
getNotificationsByMonitorId,
|
||||
deleteNotificationsByMonitorId,
|
||||
getAppSettings,
|
||||
updateAppSettings,
|
||||
};
|
||||
|
||||
@@ -12,6 +12,22 @@ const getAppSettings = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const updateAppSettings = async (newSettings) => {
|
||||
try {
|
||||
const settings = await AppSettings.findOneAndUpdate(
|
||||
{},
|
||||
{ $set: newSettings },
|
||||
{ new: true }
|
||||
);
|
||||
return settings;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "updateAppSettings";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getAppSettings,
|
||||
updateAppSettings,
|
||||
};
|
||||
|
||||
@@ -126,12 +126,17 @@ const startApp = async () => {
|
||||
|
||||
// Create services
|
||||
await connectDbAndRunServer(app, db);
|
||||
const emailService = new EmailService();
|
||||
const networkService = new NetworkService(db, emailService);
|
||||
const jobQueue = await JobQueue.createJobQueue(db, networkService);
|
||||
const pageSpeedService = new PageSpeedService();
|
||||
const settingsService = new SettingsService();
|
||||
settingsService.loadSettings();
|
||||
|
||||
await settingsService.loadSettings();
|
||||
const emailService = new EmailService(settingsService);
|
||||
const networkService = new NetworkService(db, emailService);
|
||||
const jobQueue = await JobQueue.createJobQueue(
|
||||
db,
|
||||
networkService,
|
||||
settingsService
|
||||
);
|
||||
const pageSpeedService = new PageSpeedService();
|
||||
|
||||
const cleanup = async () => {
|
||||
if (cleaningUp) {
|
||||
|
||||
@@ -27,7 +27,8 @@ const isAllowed = (allowedRoles) => {
|
||||
// Parse the token
|
||||
try {
|
||||
const parsedToken = token.slice(TOKEN_PREFIX.length, token.length);
|
||||
var decoded = jwt.verify(parsedToken, process.env.JWT_SECRET);
|
||||
const { jwtSecret } = req.settingsService.getSettings();
|
||||
var decoded = jwt.verify(parsedToken, jwtSecret);
|
||||
const userRoles = decoded.role;
|
||||
|
||||
// Check if the user has the required role
|
||||
|
||||
@@ -35,7 +35,9 @@ const verifyJWT = (req, res, next) => {
|
||||
|
||||
const parsedToken = token.slice(TOKEN_PREFIX.length, token.length);
|
||||
// Verify the token's authenticity
|
||||
jwt.verify(parsedToken, process.env.JWT_SECRET, (err, decoded) => {
|
||||
const { jwtSecret } = req.settingsService.getSettings();
|
||||
|
||||
jwt.verify(parsedToken, jwtSecret, (err, decoded) => {
|
||||
if (err) {
|
||||
return res
|
||||
.status(401)
|
||||
|
||||
@@ -33,7 +33,9 @@ const verifySuperAdmin = (req, res, next) => {
|
||||
|
||||
const parsedToken = token.slice(TOKEN_PREFIX.length, token.length);
|
||||
// verify admin role is present
|
||||
jwt.verify(parsedToken, process.env.JWT_SECRET, (err, decoded) => {
|
||||
const { jwtSecret } = req.settingsService.getSettings();
|
||||
|
||||
jwt.verify(parsedToken, jwtSecret, (err, decoded) => {
|
||||
if (err) {
|
||||
logger.error(errorMessages.INVALID_AUTH_TOKEN, {
|
||||
service: SERVICE_NAME,
|
||||
|
||||
@@ -51,15 +51,19 @@ const AppSettingsSchema = mongoose.Schema(
|
||||
},
|
||||
systemEmailHost: {
|
||||
type: String,
|
||||
default: "smtp.gmail.com",
|
||||
},
|
||||
systemEmailPort: {
|
||||
type: Number,
|
||||
default: 465,
|
||||
},
|
||||
systemEmailAddress: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
systemEmailAddress: {
|
||||
systemEmailPassword: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
singleton: {
|
||||
type: Boolean,
|
||||
|
||||
@@ -4,5 +4,10 @@ const { isAllowed } = require("../middleware/isAllowed");
|
||||
const Monitor = require("../models/Monitor");
|
||||
|
||||
router.get("/", isAllowed(["superadmin"]), settingsController.getAppSettings);
|
||||
router.put(
|
||||
"/",
|
||||
isAllowed(["superadmin"]),
|
||||
settingsController.updateAppSettings
|
||||
);
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -13,7 +13,8 @@ class EmailService {
|
||||
/**
|
||||
* Constructs an instance of the EmailService, initializing template loaders and the email transporter.
|
||||
*/
|
||||
constructor() {
|
||||
constructor(settingsService) {
|
||||
this.settingsService = settingsService;
|
||||
/**
|
||||
* Loads an email template from the filesystem.
|
||||
*
|
||||
@@ -54,15 +55,26 @@ class EmailService {
|
||||
* The email transporter used to send emails.
|
||||
* @type {Object}
|
||||
*/
|
||||
this.transporter = nodemailer.createTransport({
|
||||
host: process.env.SYSTEM_EMAIL_HOST,
|
||||
port: process.env.SYSTEM_EMAIL_PORT,
|
||||
secure: true, // Use `true` for port 465, `false` for all other ports
|
||||
|
||||
const {
|
||||
systemEmailHost,
|
||||
systemEmailPort,
|
||||
systemEmailAddress,
|
||||
systemEmailPassword,
|
||||
} = this.settingsService.getSettings();
|
||||
|
||||
const emailConfig = {
|
||||
host: systemEmailHost,
|
||||
port: systemEmailPort,
|
||||
secure: true,
|
||||
auth: {
|
||||
user: process.env.SYSTEM_EMAIL_ADDRESS,
|
||||
pass: process.env.SYSTEM_EMAIL_PASSWORD,
|
||||
user: systemEmailAddress,
|
||||
pass: systemEmailPassword,
|
||||
},
|
||||
});
|
||||
};
|
||||
console.log(emailConfig);
|
||||
|
||||
this.transporter = nodemailer.createTransport(emailConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
const { Queue, Worker, Job } = require("bullmq");
|
||||
const QUEUE_NAME = "monitors";
|
||||
const connection = {
|
||||
host: process.env.REDIS_HOST || "127.0.0.1",
|
||||
port: process.env.REDIS_PORT || 6379,
|
||||
};
|
||||
|
||||
const JOBS_PER_WORKER = 5;
|
||||
const logger = require("../utils/logger");
|
||||
const { errorMessages, successMessages } = require("../utils/messages");
|
||||
@@ -15,13 +12,20 @@ class JobQueue {
|
||||
* @constructor
|
||||
* @throws {Error}
|
||||
*/
|
||||
constructor(networkService) {
|
||||
constructor(settingsService) {
|
||||
const { redisHost, redisPort } = settingsService.getSettings();
|
||||
const connection = {
|
||||
host: redisHost || "127.0.0.1",
|
||||
port: redisPort || 6379,
|
||||
};
|
||||
this.connection = connection;
|
||||
this.queue = new Queue(QUEUE_NAME, {
|
||||
connection,
|
||||
});
|
||||
this.workers = [];
|
||||
this.db = null;
|
||||
this.networkService = null;
|
||||
this.settingsService = settingsService;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -31,8 +35,8 @@ class JobQueue {
|
||||
* @returns {Promise<JobQueue>} - Returns a new JobQueue
|
||||
*
|
||||
*/
|
||||
static async createJobQueue(db, networkService) {
|
||||
const queue = new JobQueue();
|
||||
static async createJobQueue(db, networkService, settingsService) {
|
||||
const queue = new JobQueue(settingsService);
|
||||
try {
|
||||
queue.db = db;
|
||||
queue.networkService = networkService;
|
||||
@@ -99,7 +103,7 @@ class JobQueue {
|
||||
}
|
||||
},
|
||||
{
|
||||
connection,
|
||||
connection: this.connection,
|
||||
}
|
||||
);
|
||||
return worker;
|
||||
|
||||
@@ -101,6 +101,7 @@ const successMessages = {
|
||||
|
||||
// App Settings
|
||||
GET_APP_SETTINGS: "Got app settings successfully",
|
||||
UPDATE_APP_SETTINGS: "Updated app settings successfully",
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -382,6 +382,26 @@ const getMaintenanceWindowsByMonitorIdParamValidation = joi.object({
|
||||
monitorId: joi.string().required(),
|
||||
});
|
||||
|
||||
//****************************************
|
||||
// SettingsValidation
|
||||
//****************************************
|
||||
const updateAppSettingsBodyValidation = joi.object({
|
||||
apiBaseUrl: joi.string().allow(""),
|
||||
logLevel: joi.string().valid("debug", "none", "error", "warn").allow(""),
|
||||
clientHost: joi.string().allow(""),
|
||||
jwtSecret: joi.string().allow(""),
|
||||
dbType: joi.string().allow(""),
|
||||
dbConnectionString: joi.string().allow(""),
|
||||
redisHost: joi.string().allow(""),
|
||||
redisPort: joi.number().allow(null, ""),
|
||||
jwtTTL: joi.string().allow(""),
|
||||
pagespeedApiKey: joi.string().allow(""),
|
||||
systemEmailHost: joi.string().allow(""),
|
||||
systemEmailPort: joi.number().allow(""),
|
||||
systemEmailAddress: joi.string().allow(""),
|
||||
systemEmailPassword: joi.string().allow(""),
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
roleValidatior,
|
||||
loginValidation,
|
||||
@@ -432,4 +452,5 @@ module.exports = {
|
||||
createMaintenanceWindowBodyValidation,
|
||||
getMaintenanceWindowsByUserIdParamValidation,
|
||||
getMaintenanceWindowsByMonitorIdParamValidation,
|
||||
updateAppSettingsBodyValidation,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user