2025-04-20 11:29:53 -07:00
import joi from "joi" ;
//****************************************
// Custom Validators
//****************************************
const roleValidatior = ( role ) => ( value , helpers ) => {
const hasRole = role . some (( role ) => value . includes ( role ));
if ( ! hasRole ) {
throw new joi . ValidationError (
`You do not have the required authorization. Required roles: ${ role . join ( ", " ) } `
);
}
return value ;
};
//****************************************
// Auth
//****************************************
const passwordPattern =
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!?@#$%^&*()\-_=+[\]{};:'",.<>~`|\\/])[A-Za-z0-9!?@#$%^&*()\-_=+[\]{};:'",.<>~`|\\/]+$/ ;
const loginValidation = joi . object ({
2025-06-08 16:33:12 +02:00
email : joi . string (). email (). required (). lowercase (),
password : joi . string (). required (),
2025-04-20 11:29:53 -07:00
});
const nameValidation = joi
. string ()
. trim ()
. max ( 50 )
2025-06-17 18:29:09 -06:00
. pattern ( /^(?=.*[\p{L}\p{Sc}])[\p{L}\p{Sc}\s'\-().]+$/u )
2025-04-20 11:29:53 -07:00
. messages ({
"string.empty" : "Name is required" ,
"string.max" : "Name must be less than 50 characters" ,
"string.pattern.base" :
2025-06-17 18:40:51 -06:00
"Names must contain at least 1 letter and may only include letters, currency symbols, spaces, apostrophes, hyphens (-), periods (.), and parentheses ()." ,
2025-04-20 11:29:53 -07:00
});
const registrationBodyValidation = joi . object ({
firstName : nameValidation . required (),
lastName : nameValidation . required (),
email : joi
. string ()
. email ()
. required ()
. custom (( value , helpers ) => {
const lowercasedValue = value . toLowerCase ();
if ( value !== lowercasedValue ) {
return helpers . message ( "Email must be in lowercase" );
}
return lowercasedValue ;
}),
password : joi . string (). min ( 8 ). required (). pattern ( passwordPattern ),
profileImage : joi . any (),
2025-04-28 10:34:49 -07:00
role : joi . array (). items ( joi . string (). valid ( "superadmin" , "admin" , "user" , "demo" )),
2025-04-20 11:29:53 -07:00
teamId : joi . string (). allow ( "" ). required (),
inviteToken : joi . string (). allow ( "" ). required (),
});
const editUserParamValidation = joi . object ({
userId : joi . string (). required (),
});
const editUserBodyValidation = joi . object ({
firstName : nameValidation . required (),
lastName : nameValidation . required (),
profileImage : joi . any (),
newPassword : joi . string (). min ( 8 ). pattern ( passwordPattern ),
password : joi . string (). min ( 8 ). pattern ( passwordPattern ),
deleteProfileImage : joi . boolean (),
});
const recoveryValidation = joi . object ({
email : joi
. string ()
. email ({ tlds : { allow : false } })
. required (),
});
const recoveryTokenValidation = joi . object ({
recoveryToken : joi . string (). required (),
});
const newPasswordValidation = joi . object ({
recoveryToken : joi . string (). required (),
password : joi . string (). min ( 8 ). required (). pattern ( passwordPattern ),
confirm : joi . string (),
});
const deleteUserParamValidation = joi . object ({
email : joi . string (). email (). required (),
});
const inviteRoleValidation = joi . object ({
roles : joi . custom ( roleValidatior ([ "admin" , "superadmin" ])). required (),
});
const inviteBodyValidation = joi . object ({
email : joi . string (). trim (). email (). required (). messages ({
"string.empty" : "Email is required" ,
"string.email" : "Must be a valid email address" ,
}),
role : joi . array (). required (),
teamId : joi . string (). required (),
});
const inviteVerificationBodyValidation = joi . object ({
token : joi . string (). required (),
});
//****************************************
// Monitors
//****************************************
const getMonitorByIdParamValidation = joi . object ({
monitorId : joi . string (). required (),
});
const getMonitorByIdQueryValidation = joi . object ({
status : joi . boolean (),
sortOrder : joi . string (). valid ( "asc" , "desc" ),
limit : joi . number (),
dateRange : joi . string (). valid ( "hour" , "day" , "week" , "month" , "all" ),
numToDisplay : joi . number (),
normalize : joi . boolean (),
});
2025-06-13 10:46:06 +08:00
const getMonitorsByTeamIdParamValidation = joi . object ({});
2025-04-20 11:29:53 -07:00
const getMonitorsByTeamIdQueryValidation = joi . object ({
limit : joi . number (),
type : joi
. alternatives ()
. try (
joi . string (). valid ( "http" , "ping" , "pagespeed" , "docker" , "hardware" , "port" ),
joi
. array ()
. items (
joi . string (). valid ( "http" , "ping" , "pagespeed" , "docker" , "hardware" , "port" )
)
),
page : joi . number (),
rowsPerPage : joi . number (),
filter : joi . string (),
field : joi . string (),
order : joi . string (). valid ( "asc" , "desc" ),
});
const getMonitorStatsByIdParamValidation = joi . object ({
monitorId : joi . string (). required (),
});
const getMonitorStatsByIdQueryValidation = joi . object ({
status : joi . string (),
limit : joi . number (),
sortOrder : joi . string (). valid ( "asc" , "desc" ),
dateRange : joi . string (). valid ( "hour" , "day" , "week" , "month" , "all" ),
numToDisplay : joi . number (),
normalize : joi . boolean (),
});
const getCertificateParamValidation = joi . object ({
monitorId : joi . string (). required (),
});
const createMonitorBodyValidation = joi . object ({
_id : joi . string (),
name : joi . string (). required (),
description : joi . string (). required (),
type : joi . string (). required (),
url : joi . string (). required (),
2025-05-06 10:26:31 -07:00
ignoreTlsErrors : joi . boolean (). default ( false ),
2025-04-20 11:29:53 -07:00
port : joi . number (),
isActive : joi . boolean (),
interval : joi . number (),
thresholds : joi . object (). keys ({
usage_cpu : joi . number (),
usage_memory : joi . number (),
usage_disk : joi . number (),
usage_temperature : joi . number (),
}),
2025-06-09 12:59:02 +08:00
notifications : joi . array (). items ( joi . string ()),
2025-04-20 11:29:53 -07:00
secret : joi . string (),
jsonPath : joi . string (). allow ( "" ),
expectedValue : joi . string (). allow ( "" ),
matchMethod : joi . string (),
});
2025-06-13 14:04:08 +08:00
const createMonitorsBodyValidation = joi . array (). items (
createMonitorBodyValidation . keys ({
userId : joi . string (). required (),
teamId : joi . string (). required (),
})
);
2025-04-20 11:29:53 -07:00
const editMonitorBodyValidation = joi . object ({
name : joi . string (),
description : joi . string (),
interval : joi . number (),
2025-06-09 12:59:02 +08:00
notifications : joi . array (). items ( joi . string ()),
2025-04-20 11:29:53 -07:00
secret : joi . string (),
2025-05-06 10:08:27 -07:00
ignoreTlsErrors : joi . boolean (),
2025-04-20 11:29:53 -07:00
jsonPath : joi . string (). allow ( "" ),
expectedValue : joi . string (). allow ( "" ),
2025-06-09 12:59:02 +08:00
matchMethod : joi . string (). allow ( null , "" ),
2025-05-01 13:47:10 -04:00
port : joi . number (). min ( 1 ). max ( 65535 ),
2025-04-20 11:29:53 -07:00
thresholds : joi . object (). keys ({
usage_cpu : joi . number (),
usage_memory : joi . number (),
usage_disk : joi . number (),
usage_temperature : joi . number (),
}),
});
const pauseMonitorParamValidation = joi . object ({
monitorId : joi . string (). required (),
});
const getMonitorURLByQueryValidation = joi . object ({
monitorURL : joi . string (). uri (). required (),
});
const getHardwareDetailsByIdParamValidation = joi . object ({
monitorId : joi . string (). required (),
});
const getHardwareDetailsByIdQueryValidation = joi . object ({
dateRange : joi . string (). valid ( "recent" , "hour" , "day" , "week" , "month" , "all" ),
});
//****************************************
// Alerts
//****************************************
const createAlertParamValidation = joi . object ({
monitorId : joi . string (). required (),
});
const createAlertBodyValidation = joi . object ({
checkId : joi . string (). required (),
monitorId : joi . string (). required (),
userId : joi . string (). required (),
status : joi . boolean (),
message : joi . string (),
notifiedStatus : joi . boolean (),
acknowledgeStatus : joi . boolean (),
});
const getAlertsByUserIdParamValidation = joi . object ({
userId : joi . string (). required (),
});
const getAlertsByMonitorIdParamValidation = joi . object ({
monitorId : joi . string (). required (),
});
const getAlertByIdParamValidation = joi . object ({
alertId : joi . string (). required (),
});
const editAlertParamValidation = joi . object ({
alertId : joi . string (). required (),
});
const editAlertBodyValidation = joi . object ({
status : joi . boolean (),
message : joi . string (),
notifiedStatus : joi . boolean (),
acknowledgeStatus : joi . boolean (),
});
const deleteAlertParamValidation = joi . object ({
alertId : joi . string (). required (),
});
//****************************************
// Checks
//****************************************
const createCheckParamValidation = joi . object ({
monitorId : joi . string (). required (),
});
const createCheckBodyValidation = joi . object ({
monitorId : joi . string (). required (),
status : joi . boolean (). required (),
responseTime : joi . number (). required (),
statusCode : joi . number (). required (),
message : joi . string (). required (),
});
const getChecksParamValidation = joi . object ({
monitorId : joi . string (). required (),
});
const getChecksQueryValidation = joi . object ({
2025-06-09 10:17:09 +08:00
type : joi . string (). valid ( "http" , "ping" , "pagespeed" , "hardware" , "docker" , "port" ),
2025-04-20 11:29:53 -07:00
sortOrder : joi . string (). valid ( "asc" , "desc" ),
limit : joi . number (),
dateRange : joi . string (). valid ( "recent" , "hour" , "day" , "week" , "month" , "all" ),
filter : joi . string (). valid ( "all" , "down" , "resolve" ),
page : joi . number (),
rowsPerPage : joi . number (),
status : joi . boolean (),
});
2025-06-13 12:04:39 +08:00
const getTeamChecksParamValidation = joi . object ({});
2025-04-20 11:29:53 -07:00
const getTeamChecksQueryValidation = joi . object ({
sortOrder : joi . string (). valid ( "asc" , "desc" ),
limit : joi . number (),
dateRange : joi . string (). valid ( "hour" , "day" , "week" , "month" , "all" ),
filter : joi . string (). valid ( "all" , "down" , "resolve" ),
page : joi . number (),
rowsPerPage : joi . number (),
status : joi . boolean (),
});
const deleteChecksParamValidation = joi . object ({
monitorId : joi . string (). required (),
});
2025-06-13 12:04:39 +08:00
const deleteChecksByTeamIdParamValidation = joi . object ({});
2025-04-20 11:29:53 -07:00
const updateChecksTTLBodyValidation = joi . object ({
ttl : joi . number (). required (),
});
//****************************************
// PageSpeedCheckValidation
//****************************************
const getPageSpeedCheckParamValidation = joi . object ({
monitorId : joi . string (). required (),
});
//Validation schema for the monitorId parameter
const createPageSpeedCheckParamValidation = joi . object ({
monitorId : joi . string (). required (),
});
//Validation schema for the monitorId body
const createPageSpeedCheckBodyValidation = joi . object ({
url : joi . string (). required (),
});
const deletePageSpeedCheckParamValidation = joi . object ({
monitorId : joi . string (). required (),
});
//****************************************
// MaintenanceWindowValidation
//****************************************
const createMaintenanceWindowBodyValidation = joi . object ({
monitors : joi . array (). items ( joi . string ()). required (),
name : joi . string (). required (),
active : joi . boolean (),
start : joi . date (). required (),
end : joi . date (). required (),
repeat : joi . number (). required (),
expiry : joi . date (),
});
const getMaintenanceWindowByIdParamValidation = joi . object ({
id : joi . string (). required (),
});
const getMaintenanceWindowsByTeamIdQueryValidation = joi . object ({
active : joi . boolean (),
page : joi . number (),
rowsPerPage : joi . number (),
field : joi . string (),
order : joi . string (). valid ( "asc" , "desc" ),
});
const getMaintenanceWindowsByMonitorIdParamValidation = joi . object ({
monitorId : joi . string (). required (),
});
const deleteMaintenanceWindowByIdParamValidation = joi . object ({
id : joi . string (). required (),
});
const editMaintenanceWindowByIdParamValidation = joi . object ({
id : joi . string (). required (),
});
const editMaintenanceByIdWindowBodyValidation = joi . object ({
active : joi . boolean (),
name : joi . string (),
repeat : joi . number (),
start : joi . date (),
end : joi . date (),
expiry : joi . date (),
monitors : joi . array (),
});
//****************************************
// SettingsValidation
//****************************************
const updateAppSettingsBodyValidation = joi . object ({
2025-05-09 13:24:47 -07:00
checkTTL : joi . number (). allow ( "" ),
2025-04-20 11:29:53 -07:00
pagespeedApiKey : joi . string (). allow ( "" ),
language : joi . string (). allow ( "" ),
2025-05-27 20:28:53 -04:00
timezone : joi . string (). allow ( "" ),
2025-05-27 09:26:15 -07:00
// showURL: joi.bool().required(),
2025-04-20 11:29:53 -07:00
systemEmailHost : joi . string (). allow ( "" ),
systemEmailPort : joi . number (). allow ( "" ),
systemEmailAddress : joi . string (). allow ( "" ),
systemEmailPassword : joi . string (). allow ( "" ),
2025-05-09 14:52:24 -07:00
systemEmailUser : joi . string (). allow ( "" ),
2025-06-13 12:22:28 +05:30
systemEmailConnectionHost : joi . string (). allow ( "" ). optional (),
systemEmailTLSServername : joi . string (). allow ( "" ). optional (),
systemEmailSecure : joi . boolean (),
systemEmailPool : joi . boolean (),
systemEmailIgnoreTLS : joi . boolean (),
systemEmailRequireTLS : joi . boolean (),
systemEmailRejectUnauthorized : joi . boolean (),
2025-04-20 11:29:53 -07:00
});
//****************************************
// Status Page Validation
//****************************************
const getStatusPageParamValidation = joi . object ({
url : joi . string (). required (),
});
const getStatusPageQueryValidation = joi . object ({
2025-06-09 10:17:09 +08:00
type : joi . string (). valid ( "uptime" ). required (),
2025-04-20 11:29:53 -07:00
timeFrame : joi . number (). optional (),
});
const createStatusPageBodyValidation = joi . object ({
2025-06-09 10:17:09 +08:00
type : joi . string (). valid ( "uptime" ). required (),
2025-04-20 11:29:53 -07:00
companyName : joi . string (). required (),
url : joi
. string ()
. pattern ( /^[a-zA-Z0-9_-]+$/ ) // Only allow alphanumeric, underscore, and hyphen
. required ()
. messages ({
"string.pattern.base" :
"URL can only contain letters, numbers, underscores, and hyphens" ,
}),
timezone : joi . string (). optional (),
color : joi . string (). optional (),
monitors : joi
. array ()
. items ( joi . string (). pattern ( /^[0-9a-fA-F]{24}$/ ))
. required ()
. messages ({
"string.pattern.base" : "Must be a valid monitor ID" ,
"array.base" : "Monitors must be an array" ,
"array.empty" : "At least one monitor is required" ,
"any.required" : "Monitors are required" ,
}),
subMonitors : joi
. array ()
. items ( joi . string (). pattern ( /^[0-9a-fA-F]{24}$/ ))
. optional (),
deleteSubmonitors : joi . boolean (). optional (),
isPublished : joi . boolean (),
showCharts : joi . boolean (). optional (),
showUptimePercentage : joi . boolean (),
});
const imageValidation = joi
. object ({
fieldname : joi . string (). required (),
originalname : joi . string (). required (),
encoding : joi . string (). required (),
mimetype : joi
. string ()
. valid ( "image/jpeg" , "image/png" , "image/jpg" )
. required ()
. messages ({
"string.valid" : "File must be a valid image (jpeg, jpg, or png)" ,
}),
size : joi . number (). max ( 3145728 ). required (). messages ({
"number.max" : "File size must be less than 3MB" ,
}),
buffer : joi . binary (). required (),
destination : joi . string (),
filename : joi . string (),
path : joi . string (),
})
. messages ({
"any.required" : "Image file is required" ,
});
const webhookConfigValidation = joi
. object ({
webhookUrl : joi
. string ()
. uri ()
. when ( "$platform" , {
switch : [
{
is : "telegram" ,
then : joi . optional (),
},
{
is : "discord" ,
then : joi . required (). messages ({
"string.empty" : "Discord webhook URL is required" ,
"string.uri" : "Discord webhook URL must be a valid URL" ,
"any.required" : "Discord webhook URL is required" ,
}),
},
{
is : "slack" ,
then : joi . required (). messages ({
"string.empty" : "Slack webhook URL is required" ,
"string.uri" : "Slack webhook URL must be a valid URL" ,
"any.required" : "Slack webhook URL is required" ,
}),
},
],
}),
botToken : joi . string (). when ( "$platform" , {
is : "telegram" ,
then : joi . required (). messages ({
"string.empty" : "Telegram bot token is required" ,
"any.required" : "Telegram bot token is required" ,
}),
otherwise : joi . optional (),
}),
chatId : joi . string (). when ( "$platform" , {
is : "telegram" ,
then : joi . required (). messages ({
"string.empty" : "Telegram chat ID is required" ,
"any.required" : "Telegram chat ID is required" ,
}),
otherwise : joi . optional (),
}),
})
. required ();
const triggerNotificationBodyValidation = joi . object ({
monitorId : joi . string (). required (). messages ({
"string.empty" : "Monitor ID is required" ,
"any.required" : "Monitor ID is required" ,
}),
type : joi . string (). valid ( "webhook" ). required (). messages ({
"string.empty" : "Notification type is required" ,
"any.required" : "Notification type is required" ,
"any.only" : "Notification type must be webhook" ,
}),
platform : joi . string (). valid ( "telegram" , "discord" , "slack" ). required (). messages ({
"string.empty" : "Platform type is required" ,
"any.required" : "Platform type is required" ,
"any.only" : "Platform must be telegram, discord, or slack" ,
}),
config : webhookConfigValidation . required (). messages ({
"any.required" : "Webhook configuration is required" ,
}),
});
2025-06-09 10:30:21 +08:00
const createNotificationBodyValidation = joi . object ({
notificationName : joi . string (). required (). messages ({
"string.empty" : "Notification name is required" ,
"any.required" : "Notification name is required" ,
}),
address : joi . when ( "type" , {
is : "email" ,
then : joi . string (). email (). required (). messages ({
"string.empty" : "E-mail address cannot be empty" ,
"any.required" : "E-mail address is required" ,
"string.email" : "Please enter a valid e-mail address" ,
}),
}),
2025-06-18 14:42:59 +08:00
type : joi
. string ()
. valid ( "email" , "webhook" , "slack" , "discord" , "pager_duty" )
. required ()
. messages ({
"string.empty" : "Notification type is required" ,
"any.required" : "Notification type is required" ,
"any.only" : "Notification type must be email, webhook, or pager_duty" ,
2025-06-09 10:30:21 +08:00
}),
});
2025-04-20 11:29:53 -07:00
//****************************************
// Announcetment Page Validation
//****************************************
const createAnnouncementValidation = joi . object ({
title : joi . string (). required (). messages ({
2025-04-28 10:34:49 -07:00
"string.empty" : "Title cannot be empty" ,
"any.required" : "Title is required" ,
2025-04-20 11:29:53 -07:00
}),
message : joi . string (). required (). messages ({
2025-04-28 10:34:49 -07:00
"string.empty" : "Message cannot be empty" ,
"any.required" : "Message is required" ,
2025-04-20 11:29:53 -07:00
}),
userId : joi . string (). required (),
2025-04-28 10:34:49 -07:00
});
2025-04-20 11:29:53 -07:00
2025-05-16 15:01:45 -07:00
const sendTestEmailBodyValidation = joi . object ({
to : joi . string (). required (),
systemEmailHost : joi . string (),
systemEmailPort : joi . number (),
2025-06-12 00:39:47 +05:30
systemEmailSecure : joi . boolean (),
systemEmailPool : joi . boolean (),
2025-05-16 15:01:45 -07:00
systemEmailAddress : joi . string (),
systemEmailPassword : joi . string (),
systemEmailUser : joi . string (),
2025-06-13 12:22:28 +05:30
systemEmailConnectionHost : joi . string (). allow ( "" ). optional (),
2025-06-12 00:39:47 +05:30
systemEmailIgnoreTLS : joi . boolean (),
systemEmailRequireTLS : joi . boolean (),
systemEmailRejectUnauthorized : joi . boolean (),
2025-06-13 12:22:28 +05:30
systemEmailTLSServername : joi . string (). allow ( "" ). optional (),
2025-05-16 15:01:45 -07:00
});
2025-04-20 11:29:53 -07:00
export {
roleValidatior ,
loginValidation ,
registrationBodyValidation ,
recoveryValidation ,
recoveryTokenValidation ,
newPasswordValidation ,
inviteRoleValidation ,
inviteBodyValidation ,
inviteVerificationBodyValidation ,
createMonitorBodyValidation ,
createMonitorsBodyValidation ,
getMonitorByIdParamValidation ,
getMonitorByIdQueryValidation ,
getMonitorsByTeamIdParamValidation ,
getMonitorsByTeamIdQueryValidation ,
getMonitorStatsByIdParamValidation ,
getMonitorStatsByIdQueryValidation ,
getHardwareDetailsByIdParamValidation ,
getHardwareDetailsByIdQueryValidation ,
getCertificateParamValidation ,
editMonitorBodyValidation ,
pauseMonitorParamValidation ,
getMonitorURLByQueryValidation ,
editUserParamValidation ,
editUserBodyValidation ,
createAlertParamValidation ,
createAlertBodyValidation ,
getAlertsByUserIdParamValidation ,
getAlertsByMonitorIdParamValidation ,
getAlertByIdParamValidation ,
editAlertParamValidation ,
editAlertBodyValidation ,
deleteAlertParamValidation ,
createCheckParamValidation ,
createCheckBodyValidation ,
getChecksParamValidation ,
getChecksQueryValidation ,
getTeamChecksParamValidation ,
getTeamChecksQueryValidation ,
deleteChecksParamValidation ,
deleteChecksByTeamIdParamValidation ,
updateChecksTTLBodyValidation ,
deleteUserParamValidation ,
getPageSpeedCheckParamValidation ,
createPageSpeedCheckParamValidation ,
deletePageSpeedCheckParamValidation ,
createPageSpeedCheckBodyValidation ,
createMaintenanceWindowBodyValidation ,
getMaintenanceWindowByIdParamValidation ,
getMaintenanceWindowsByTeamIdQueryValidation ,
getMaintenanceWindowsByMonitorIdParamValidation ,
deleteMaintenanceWindowByIdParamValidation ,
editMaintenanceWindowByIdParamValidation ,
editMaintenanceByIdWindowBodyValidation ,
updateAppSettingsBodyValidation ,
createStatusPageBodyValidation ,
getStatusPageParamValidation ,
getStatusPageQueryValidation ,
imageValidation ,
triggerNotificationBodyValidation ,
2025-06-09 10:30:21 +08:00
createNotificationBodyValidation ,
2025-04-20 11:29:53 -07:00
webhookConfigValidation ,
2025-04-28 10:34:49 -07:00
createAnnouncementValidation ,
2025-05-16 15:01:45 -07:00
sendTestEmailBodyValidation ,
2025-04-20 11:29:53 -07:00
};