sensor and location done and some cleanupd
testing will be required
This commit is contained in:
parent
940d40ed38
commit
5c3a43ddd6
42
Sean/modules/otpUtils.js
Normal file
42
Sean/modules/otpUtils.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
const nodemailer = require("nodemailer");
|
||||||
|
const otpGenerator = require('otp-generator');
|
||||||
|
const path = require('path')
|
||||||
|
require('dotenv').config({ path: path.resolve(__dirname, '../.env') })
|
||||||
|
|
||||||
|
const generateOTP = () => {
|
||||||
|
const otp = otpGenerator.generate(6, { upperCase: false, specialChars: false });
|
||||||
|
const expirationTime = Date.now() + 5 * 60 * 1000; // 5 minutes expiration
|
||||||
|
return { otp, expirationTime };
|
||||||
|
};
|
||||||
|
const sendOTPByEmail = async (email, otp) => {
|
||||||
|
try {
|
||||||
|
const transporter = nodemailer.createTransport({
|
||||||
|
service: 'gmail',
|
||||||
|
host: 'smtp.gmail.com',
|
||||||
|
port: 587, // use the appropriate port for your SMTP server
|
||||||
|
secure: false, // true for 465, false for other ports
|
||||||
|
auth: {
|
||||||
|
user: process.env.euser, // replace with your email
|
||||||
|
pass: process.env.epass // replace with your email password
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const mailOptions = {
|
||||||
|
from: process.env.euser,
|
||||||
|
to: email,
|
||||||
|
subject: 'Login OTP',
|
||||||
|
text: `Your OTP for login is: ${otp}`
|
||||||
|
};
|
||||||
|
|
||||||
|
await transporter.sendMail(mailOptions);
|
||||||
|
console.log('OTP sent successfully to', email);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error sending OTP:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
generateOTP,
|
||||||
|
sendOTPByEmail
|
||||||
|
};
|
9
Sean/modules/rateLimitMiddleware.js
Normal file
9
Sean/modules/rateLimitMiddleware.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
const rateLimit = require('express-rate-limit');
|
||||||
|
|
||||||
|
const limiter = rateLimit({
|
||||||
|
windowMs: 15 * 60 * 1000, // 15 minutes
|
||||||
|
max: 5, // limit each IP to 5 requests per windowMs
|
||||||
|
message: 'Too many login attempts from this IP, please try again later.',
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = limiter;
|
77
Sean/modules/validationMiddleware.js
Normal file
77
Sean/modules/validationMiddleware.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
const { body } = require('express-validator');
|
||||||
|
|
||||||
|
const locationValidation = [
|
||||||
|
body('name').trim().isLength({ min: 1 }).withMessage('Name must not be empty').escape(),
|
||||||
|
body('added_by').trim().isLength({ min: 1 }).withMessage('Added by must not be empty').escape(),
|
||||||
|
body('description').trim().escape(),
|
||||||
|
];
|
||||||
|
|
||||||
|
const locationValidationUpdate = [
|
||||||
|
body('id').trim().escape(),
|
||||||
|
body('name').trim().isLength({ min: 1 }).withMessage('Name must not be empty').escape(),
|
||||||
|
body('added_by').trim().isLength({ min: 1 }).withMessage('Added by must not be empty').escape(),
|
||||||
|
body('description').trim().escape(),
|
||||||
|
];
|
||||||
|
|
||||||
|
const locationdeleteValidation = [
|
||||||
|
body('id').trim().escape()
|
||||||
|
];
|
||||||
|
|
||||||
|
const sensorValidation = [
|
||||||
|
body('sensorname').trim().isLength({ min: 1 }).withMessage('Sensor Name must not be empty').escape(),
|
||||||
|
body('added_by').trim().isLength({ min: 1 }).withMessage('Added by must not be empty').escape(),
|
||||||
|
body('macAddress').custom(value => {
|
||||||
|
const macAddressRegex = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/;
|
||||||
|
if (!macAddressRegex.test(value)) {
|
||||||
|
throw new Error('Invalid MAC address format');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}).withMessage('Invalid MAC address format').escape(),
|
||||||
|
body('description').trim().escape(),
|
||||||
|
body('location').trim().escape()
|
||||||
|
];
|
||||||
|
|
||||||
|
const sensorupdateValidation = [
|
||||||
|
body('id').trim().escape(),
|
||||||
|
body('sensorname').trim().isLength({ min: 1 }).withMessage('Sensor Name must not be empty').escape(),
|
||||||
|
body('added_by').trim().isLength({ min: 1 }).withMessage('Added by must not be empty').escape(),
|
||||||
|
body('macAddress').custom(value => {
|
||||||
|
const macAddressRegex = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/;
|
||||||
|
if (!macAddressRegex.test(value)) {
|
||||||
|
throw new Error('Invalid MAC address format');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}).withMessage('Invalid MAC address format').escape(),
|
||||||
|
body('description').trim().escape(),
|
||||||
|
body('location').trim().escape()
|
||||||
|
];
|
||||||
|
|
||||||
|
const sensordeleteValidation = [
|
||||||
|
body('id').trim().escape()
|
||||||
|
];
|
||||||
|
|
||||||
|
const loginValidation = [
|
||||||
|
body('username').escape().trim().isLength({ min: 1 }).withMessage('Username must not be empty'),
|
||||||
|
body('password').escape().trim().isLength({ min: 1 }).withMessage('Password must not be empty'),
|
||||||
|
];
|
||||||
|
|
||||||
|
const otpValidation = [
|
||||||
|
body('otp').escape().trim().isLength({ min: 1 }).withMessage('OTP must not be empty'),
|
||||||
|
];
|
||||||
|
|
||||||
|
const createValidation = [
|
||||||
|
body('name').trim().isLength({ min: 1 }).withMessage('Name must not be empty').escape(),
|
||||||
|
body('username').trim().isLength({ min: 1 }).withMessage('Username must not be empty').escape(),
|
||||||
|
body('email').isEmail().withMessage('Invalid email address').normalizeEmail(),
|
||||||
|
body('password').custom((value) => {
|
||||||
|
if (!isStrongPassword(value)) { throw new Error('Password does not meet complexity requirements'); } return true;
|
||||||
|
}),
|
||||||
|
body('jobTitle').trim().isLength({ min: 1 }).withMessage('Job title must not be empty').escape(),
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
locationValidation,locationValidationUpdate,locationdeleteValidation
|
||||||
|
,sensorValidation,sensorupdateValidation,sensordeleteValidation,loginValidation,otpValidation
|
||||||
|
,createValidation
|
||||||
|
};
|
278
Sean/server.js
278
Sean/server.js
@ -1,21 +1,23 @@
|
|||||||
const express = require("express");
|
const express = require("express");
|
||||||
const session = require("express-session");
|
const session = require("express-session");
|
||||||
const rateLimit = require('express-rate-limit');
|
|
||||||
const cookieParser = require('cookie-parser');
|
const cookieParser = require('cookie-parser');
|
||||||
const bodyParser = require("body-parser");
|
const bodyParser = require("body-parser");
|
||||||
const bcrypt = require("bcrypt");
|
const bcrypt = require("bcrypt");
|
||||||
const crypto = require("crypto");
|
const crypto = require("crypto");
|
||||||
const nodemailer = require("nodemailer");
|
|
||||||
const otpGenerator = require('otp-generator');
|
|
||||||
const { body, validationResult } = require('express-validator');
|
|
||||||
const validator = require('validator');
|
const validator = require('validator');
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
|
|
||||||
|
const {validationResult } = require('express-validator');
|
||||||
|
const {locationValidation, locationValidationUpdate, locationdeleteValidation
|
||||||
|
,sensorValidation, sensorupdateValidation, sensordeleteValidation, loginValidation
|
||||||
|
,otpValidation, createValidation} = require('./modules/validationMiddleware');
|
||||||
|
const rateLimit = require('./modules/rateLimitMiddleware');
|
||||||
|
const { generateOTP, sendOTPByEmail } = require('./modules/otpUtils');
|
||||||
const { format } = require('date-fns');
|
const { format } = require('date-fns');
|
||||||
const { Sequelize } = require('sequelize');
|
const { Sequelize } = require('sequelize');
|
||||||
const { transporter } = require("./modules/nodeMailer");
|
const { transporter } = require("./modules/nodeMailer");
|
||||||
const { sequelize, User } = require("./modules/mysql");
|
const { sequelize, User } = require("./modules/mysql");
|
||||||
const userLogs= require('./models/userLogs')(sequelize); // Adjust the path based on your project structure
|
const userLogs= require('./models/userLogs')(sequelize);
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
app.use(bodyParser.urlencoded({ extended: true }));
|
app.use(bodyParser.urlencoded({ extended: true }));
|
||||||
@ -28,7 +30,6 @@ app.use(bodyParser.urlencoded({ extended: true }));
|
|||||||
|
|
||||||
app.set("view engine", "ejs");
|
app.set("view engine", "ejs");
|
||||||
|
|
||||||
|
|
||||||
app.use(session({
|
app.use(session({
|
||||||
secret: process.env.key,
|
secret: process.env.key,
|
||||||
resave: false,
|
resave: false,
|
||||||
@ -46,76 +47,27 @@ function isAuthenticated(req, res, next) {
|
|||||||
res.redirect("/login");
|
res.redirect("/login");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const generateOTP = () => {
|
|
||||||
const otp = otpGenerator.generate(6, { upperCase: false, specialChars: false });
|
|
||||||
const expirationTime = Date.now() + 5 * 60 * 1000; // 5 minutes expiration
|
|
||||||
return { otp, expirationTime };
|
|
||||||
};
|
|
||||||
|
|
||||||
const sendOTPByEmail = async (email, otp) => {
|
|
||||||
try {
|
|
||||||
const transporter = nodemailer.createTransport({
|
|
||||||
service: 'gmail',
|
|
||||||
auth: {
|
|
||||||
user: process.env.euser, // replace with your email
|
|
||||||
pass: process.env.epass // replace with your email password
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const mailOptions = {
|
|
||||||
from: process.env.euser,
|
|
||||||
to: email,
|
|
||||||
subject: 'Login OTP',
|
|
||||||
text: `Your OTP for login is: ${otp}`
|
|
||||||
};
|
|
||||||
|
|
||||||
await transporter.sendMail(mailOptions);
|
|
||||||
console.log('OTP sent successfully to', email);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error sending OTP:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
app.get("/login", (req, res) => {
|
app.get("/login", (req, res) => {
|
||||||
|
|
||||||
res.render("login", { error: null });
|
res.render("login", { error: null });
|
||||||
});
|
});
|
||||||
|
|
||||||
const limiter = rateLimit({
|
app.use('/login', rateLimit);
|
||||||
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
||||||
max: 5, // limit each IP to 3 requests per windowMs
|
|
||||||
message: 'Too many login attempts from this IP, please try again later.',
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use('/login', limiter);
|
|
||||||
|
|
||||||
|
|
||||||
app.post('/login', [
|
|
||||||
body('username').escape().trim().isLength({ min: 1 }).withMessage('Username must not be empty'),
|
|
||||||
body('password').escape().trim().isLength({ min: 1 }).withMessage('Password must not be empty'),
|
|
||||||
],
|
|
||||||
async (req, res) => {
|
|
||||||
try {
|
|
||||||
const errors = validationResult(req);
|
|
||||||
|
|
||||||
|
app.post('/login', loginValidation, async (req, res) => {
|
||||||
|
try {const errors = validationResult(req);
|
||||||
if (!errors.isEmpty()) {
|
if (!errors.isEmpty()) {
|
||||||
return res.render('login', { error: 'Invalid input. Please check your credentials.', csrfToken: req.session.csrfToken });
|
return res.render('login', { error: 'Invalid input. Please check your credentials.', csrfToken: req.session.csrfToken });
|
||||||
}
|
}
|
||||||
|
|
||||||
let { username, password } = req.body;
|
let { username, password } = req.body;
|
||||||
username = username.trim();
|
username = username.trim();
|
||||||
|
|
||||||
const user = await User.findOne({ where: { username } });
|
const user = await User.findOne({ where: { username } });
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
const isLoginSuccessful = await bcrypt.compare(password, user.password);
|
const isLoginSuccessful = await bcrypt.compare(password, user.password);
|
||||||
|
|
||||||
if (isLoginSuccessful) {
|
if (isLoginSuccessful) {
|
||||||
await userLogs.create({ username, success: true, activity: "Credentials entered correctly" });
|
await userLogs.create({ username, success: true, activity: "Credentials entered correctly" });
|
||||||
|
|
||||||
|
|
||||||
const { otp, expirationTime } = generateOTP();
|
const { otp, expirationTime } = generateOTP();
|
||||||
|
|
||||||
req.session.otp = otp;
|
req.session.otp = otp;
|
||||||
@ -161,17 +113,12 @@ async (req, res) => {
|
|||||||
|
|
||||||
|
|
||||||
// OTP verification route
|
// OTP verification route
|
||||||
app.post("/verify-otp", [
|
app.post("/verify-otp", otpValidation ,async (req, res) => {
|
||||||
body('otp').escape().trim().isLength({ min: 1 }).withMessage('OTP must not be empty'),
|
|
||||||
],
|
|
||||||
async (req, res) => {
|
|
||||||
try {
|
try {
|
||||||
const errors = validationResult(req);
|
const errors = validationResult(req);
|
||||||
|
|
||||||
if (!errors.isEmpty()) {
|
if (!errors.isEmpty()) {
|
||||||
return res.render('otp', { error: 'Invalid OTP. Please try again.'});
|
return res.render('otp', { error: 'Invalid OTP. Please try again.'});
|
||||||
}
|
}
|
||||||
|
|
||||||
const enteredOTP = req.body.otp;
|
const enteredOTP = req.body.otp;
|
||||||
|
|
||||||
if (!req.session) {
|
if (!req.session) {
|
||||||
@ -209,17 +156,10 @@ app.post("/verify-otp", [
|
|||||||
req.session.authenticated = true;
|
req.session.authenticated = true;
|
||||||
req.session.username = req.body.username;
|
req.session.username = req.body.username;
|
||||||
req.session.sessionToken = sessionToken;
|
req.session.sessionToken = sessionToken;
|
||||||
|
|
||||||
|
|
||||||
csrfTokenSession = crypto.randomBytes(32).toString('hex');
|
csrfTokenSession = crypto.randomBytes(32).toString('hex');
|
||||||
|
|
||||||
// Log anti-CSRF token
|
|
||||||
console.log(`Generated Anti-CSRF Token: ${csrfTokenSession}`);
|
|
||||||
|
|
||||||
res.cookie('sessionToken', sessionToken, { secure: true, httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000) }); // Expires in 1 day
|
res.cookie('sessionToken', sessionToken, { secure: true, httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000) }); // Expires in 1 day
|
||||||
|
|
||||||
console.log(`Generated Session Token: ${sessionToken}`);
|
|
||||||
|
|
||||||
res.redirect("/home");
|
res.redirect("/home");
|
||||||
} else {
|
} else {
|
||||||
if (req.body.username) {
|
if (req.body.username) {
|
||||||
@ -262,16 +202,13 @@ app.post("/verify-otp", [
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get("/home", isAuthenticated, async (req, res) => {
|
||||||
|
|
||||||
|
const response = await axios.get(process.env.API_ALLLOCATION);
|
||||||
app.get("/home", isAuthenticated, (req, res) => {
|
const valueData = response.data;
|
||||||
// Render the home page with sensor data
|
console.log = (valueData);
|
||||||
res.render("home", {
|
res.render("home", { username: req.session.username, valueData});
|
||||||
username: req.session.username,
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
app.get("/inusers", isAuthenticated, async (req, res) => {
|
app.get("/inusers", isAuthenticated, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
@ -318,20 +255,8 @@ function isStrongPassword(password) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
app.post(
|
app.post(
|
||||||
'/createUser',
|
'/createUser', createValidation, async (req, res) => {
|
||||||
[
|
|
||||||
body('name').trim().isLength({ min: 1 }).withMessage('Name must not be empty').escape(),
|
|
||||||
body('username').trim().isLength({ min: 1 }).withMessage('Username must not be empty').escape(),
|
|
||||||
body('email').isEmail().withMessage('Invalid email address').normalizeEmail(),
|
|
||||||
body('password').custom((value) => {
|
|
||||||
if (!isStrongPassword(value)) { throw new Error('Password does not meet complexity requirements'); } return true;
|
|
||||||
}),
|
|
||||||
body('jobTitle').trim().isLength({ min: 1 }).withMessage('Job title must not be empty').escape(),
|
|
||||||
],
|
|
||||||
async (req, res) => {
|
|
||||||
try {
|
try {
|
||||||
const errors = validationResult(req);
|
const errors = validationResult(req);
|
||||||
|
|
||||||
@ -463,24 +388,13 @@ app.post("/forgot-password", async (req, res) => {
|
|||||||
const error = "Username or email not found.";
|
const error = "Username or email not found.";
|
||||||
return res.render("forgot-password", { error, success: null });
|
return res.render("forgot-password", { error, success: null });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate reset token and update the user
|
// Generate reset token and update the user
|
||||||
const reset_token = crypto.randomBytes(20).toString("hex");
|
const reset_token = crypto.randomBytes(20).toString("hex");
|
||||||
const reset_token_expiry = new Date(Date.now() + 3600000); // Token expires in 1 hour
|
const reset_token_expiry = new Date(Date.now() + 3600000); // Token expires in 1 hour
|
||||||
|
|
||||||
// Update the user with the reset token and expiry
|
// Update the user with the reset token and expiry
|
||||||
await User.update(
|
await User.update({reset_token,reset_token_expiry,},
|
||||||
{
|
{where: {id: user.id},}
|
||||||
reset_token,
|
|
||||||
reset_token_expiry,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
where: {
|
|
||||||
id: user.id, // Replace 'id' with the actual primary key field of your User model
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Send email with reset link
|
// Send email with reset link
|
||||||
const resetLink = `http://localhost:3000/reset-password/${reset_token}`;
|
const resetLink = `http://localhost:3000/reset-password/${reset_token}`;
|
||||||
const mailOptions = {
|
const mailOptions = {
|
||||||
@ -488,12 +402,9 @@ app.post("/forgot-password", async (req, res) => {
|
|||||||
subject: "Password Reset",
|
subject: "Password Reset",
|
||||||
text: `Click on the following link to reset your password: ${resetLink}`,
|
text: `Click on the following link to reset your password: ${resetLink}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
await transporter.sendMail(mailOptions);
|
await transporter.sendMail(mailOptions);
|
||||||
|
|
||||||
const success = "Password reset email sent successfully. Check your inbox.";
|
const success = "Password reset email sent successfully. Check your inbox.";
|
||||||
res.render("forgot-password", { error: null, success });
|
res.render("forgot-password", { error: null, success });
|
||||||
|
|
||||||
// Log the successful sending of the reset link in the database
|
// Log the successful sending of the reset link in the database
|
||||||
await userLogs.create({
|
await userLogs.create({
|
||||||
username: user.username,
|
username: user.username,
|
||||||
@ -509,29 +420,22 @@ app.post("/forgot-password", async (req, res) => {
|
|||||||
console.error("Error during password reset:", error);
|
console.error("Error during password reset:", error);
|
||||||
const errorMessage = "An error occurred during the password reset process.";
|
const errorMessage = "An error occurred during the password reset process.";
|
||||||
res.render("forgot-password", { error: errorMessage, success: null });
|
res.render("forgot-password", { error: errorMessage, success: null });
|
||||||
}
|
}});
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
app.post("/reset-password/:token", async (req, res) => {
|
app.post("/reset-password/:token", async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { token } = req.params;
|
const { token } = req.params;
|
||||||
const { password, confirmPassword } = req.body;
|
const { password, confirmPassword } = req.body;
|
||||||
|
|
||||||
// Sanitize the inputs
|
// Sanitize the inputs
|
||||||
const sanitizedToken = validator.escape(token);
|
const sanitizedToken = validator.escape(token);
|
||||||
const sanitizedPassword = validator.escape(password);
|
const sanitizedPassword = validator.escape(password);
|
||||||
const sanitizedConfirmPassword = validator.escape(confirmPassword);
|
const sanitizedConfirmPassword = validator.escape(confirmPassword);
|
||||||
|
|
||||||
// Find user with matching reset token and not expired
|
// Find user with matching reset token and not expired
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
where: {
|
where: {reset_token: sanitizedToken,
|
||||||
reset_token: sanitizedToken,
|
|
||||||
reset_token_expiry: { [Sequelize.Op.gt]: new Date() },
|
reset_token_expiry: { [Sequelize.Op.gt]: new Date() },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
// Pass the error to the template when rendering the reset-password page
|
// Pass the error to the template when rendering the reset-password page
|
||||||
return res.render("reset-password", {
|
return res.render("reset-password", {
|
||||||
@ -539,7 +443,6 @@ app.post("/forgot-password", async (req, res) => {
|
|||||||
resetError: "Invalid or expired reset token",
|
resetError: "Invalid or expired reset token",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if passwords match
|
// Check if passwords match
|
||||||
if (sanitizedPassword !== sanitizedConfirmPassword) {
|
if (sanitizedPassword !== sanitizedConfirmPassword) {
|
||||||
// Pass the error to the template when rendering the reset-password page
|
// Pass the error to the template when rendering the reset-password page
|
||||||
@ -548,31 +451,24 @@ app.post("/forgot-password", async (req, res) => {
|
|||||||
resetError: "Passwords do not match",
|
resetError: "Passwords do not match",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the new password meets complexity requirements
|
// Check if the new password meets complexity requirements
|
||||||
if (!isStrongPassword(sanitizedPassword)) {
|
if (!isStrongPassword(sanitizedPassword)) {
|
||||||
// Pass the error to the template when rendering the reset-password page
|
// Pass the error to the template when rendering the reset-password page
|
||||||
return res.render("reset-password", {
|
return res.render("reset-password", {
|
||||||
token,
|
token, resetError:
|
||||||
resetError:
|
|
||||||
"Password does not meet complexity requirements. It must be at least 10 characters long and include at least one uppercase letter, one lowercase letter, one digit, and one symbol.",
|
"Password does not meet complexity requirements. It must be at least 10 characters long and include at least one uppercase letter, one lowercase letter, one digit, and one symbol.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash the new password
|
// Hash the new password
|
||||||
const saltRounds = 10;
|
const saltRounds = 10;
|
||||||
const hashedPassword = await bcrypt.hash(sanitizedPassword, saltRounds);
|
const hashedPassword = await bcrypt.hash(sanitizedPassword, saltRounds);
|
||||||
|
|
||||||
// Update user's password and clear reset token
|
// Update user's password and clear reset token
|
||||||
const updateQuery = {
|
const updateQuery = {
|
||||||
password: hashedPassword,
|
password: hashedPassword,
|
||||||
reset_token: null,
|
reset_token: null,
|
||||||
reset_token_expiry: null,
|
reset_token_expiry: null,
|
||||||
};
|
};
|
||||||
const whereCondition = {
|
const whereCondition = {reset_token: sanitizedToken,};
|
||||||
reset_token: sanitizedToken,
|
|
||||||
};
|
|
||||||
|
|
||||||
await User.update(updateQuery, {
|
await User.update(updateQuery, {
|
||||||
where: whereCondition,
|
where: whereCondition,
|
||||||
});
|
});
|
||||||
@ -619,10 +515,8 @@ app.post("/reset-password", async (req, res) => {
|
|||||||
return res.status(403).json({ error: 'CSRF token mismatch' });
|
return res.status(403).json({ error: 'CSRF token mismatch' });
|
||||||
}
|
}
|
||||||
const sessionTokencookie = req.cookies['sessionToken'];
|
const sessionTokencookie = req.cookies['sessionToken'];
|
||||||
|
|
||||||
// Verify sessionToken with the one stored in the database
|
// Verify sessionToken with the one stored in the database
|
||||||
const user = await User.findOne({ where: { sessionid: sessionTokencookie } });
|
const user = await User.findOne({ where: { sessionid: sessionTokencookie } });
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return res.status(403).json({ error: 'Invalid sessionToken' });
|
return res.status(403).json({ error: 'Invalid sessionToken' });
|
||||||
}
|
}
|
||||||
@ -630,12 +524,10 @@ app.post("/reset-password", async (req, res) => {
|
|||||||
const sanitizedUsername = validator.escape(username);
|
const sanitizedUsername = validator.escape(username);
|
||||||
const sanitizedPassword = validator.escape(password);
|
const sanitizedPassword = validator.escape(password);
|
||||||
const sanitizedConfirmPassword = validator.escape(confirmPassword);
|
const sanitizedConfirmPassword = validator.escape(confirmPassword);
|
||||||
|
|
||||||
// Check if passwords match
|
// Check if passwords match
|
||||||
if (sanitizedPassword !== sanitizedConfirmPassword) {
|
if (sanitizedPassword !== sanitizedConfirmPassword) {
|
||||||
return res.status(400).json({ error: "Passwords do not match" });
|
return res.status(400).json({ error: "Passwords do not match" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the new password meets complexity requirements
|
// Check if the new password meets complexity requirements
|
||||||
if (!isStrongPassword(sanitizedPassword)) {
|
if (!isStrongPassword(sanitizedPassword)) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
@ -643,31 +535,25 @@ app.post("/reset-password", async (req, res) => {
|
|||||||
"Password does not meet complexity requirements. It must be at least 10 characters long and include at least one uppercase letter, one lowercase letter, one digit, and one symbol.",
|
"Password does not meet complexity requirements. It must be at least 10 characters long and include at least one uppercase letter, one lowercase letter, one digit, and one symbol.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Find the user in the database
|
// Find the user in the database
|
||||||
const user = await User.findOne({ where: { username: sanitizedUsername } });
|
const user = await User.findOne({ where: { username: sanitizedUsername } });
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return res.status(404).json({ error: "User does not exist" });
|
return res.status(404).json({ error: "User does not exist" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a random salt and hash the new password
|
// Generate a random salt and hash the new password
|
||||||
const saltRounds = 10;
|
const saltRounds = 10;
|
||||||
const hashedPassword = await bcrypt.hash(sanitizedPassword, saltRounds);
|
const hashedPassword = await bcrypt.hash(sanitizedPassword, saltRounds);
|
||||||
|
|
||||||
// Update user's password
|
// Update user's password
|
||||||
await User.update(
|
await User.update(
|
||||||
{ password: hashedPassword },
|
{ password: hashedPassword },
|
||||||
{ where: { username: sanitizedUsername } }
|
{ where: { username: sanitizedUsername } }
|
||||||
);
|
);
|
||||||
|
|
||||||
// Log password reset activity
|
// Log password reset activity
|
||||||
await userLogs.create({
|
await userLogs.create({
|
||||||
username: creatorUsername,
|
username: creatorUsername,
|
||||||
activity: `Password has been reset for ${sanitizedUsername}`,
|
activity: `Password has been reset for ${sanitizedUsername}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Password update successful
|
// Password update successful
|
||||||
return res.status(200).json({ success: "Password updated successfully" });
|
return res.status(200).json({ success: "Password updated successfully" });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -679,10 +565,8 @@ app.post("/reset-password", async (req, res) => {
|
|||||||
|
|
||||||
app.get('/searchUser', async (req, res) => {
|
app.get('/searchUser', async (req, res) => {
|
||||||
const { username } = req.query;
|
const { username } = req.query;
|
||||||
|
|
||||||
// Sanitize the input
|
// Sanitize the input
|
||||||
const sanitizedUsername = validator.escape(username);
|
const sanitizedUsername = validator.escape(username);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Find the user in the database
|
// Find the user in the database
|
||||||
const user = await User.findOne({ where: { username: sanitizedUsername } });
|
const user = await User.findOne({ where: { username: sanitizedUsername } });
|
||||||
@ -690,11 +574,7 @@ app.get('/searchUser', async (req, res) => {
|
|||||||
if (!user) {
|
if (!user) {
|
||||||
// No user found with the given username
|
// No user found with the given username
|
||||||
res.status(404).json({ success: false, error: 'User not found' });
|
res.status(404).json({ success: false, error: 'User not found' });
|
||||||
} else {
|
} else {res.json(user)}
|
||||||
// User found, return user data
|
|
||||||
res.json(user);
|
|
||||||
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Sequelize query error:', error);
|
console.error('Sequelize query error:', error);
|
||||||
res.status(500).json({ success: false, error: 'Internal Server Error' });
|
res.status(500).json({ success: false, error: 'Internal Server Error' });
|
||||||
@ -705,7 +585,6 @@ app.get('/api/users', async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
// Find all users in the database
|
// Find all users in the database
|
||||||
const users = await User.findAll();
|
const users = await User.findAll();
|
||||||
|
|
||||||
// Return the users in the response
|
// Return the users in the response
|
||||||
res.json(users);
|
res.json(users);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -774,9 +653,6 @@ app.delete('/api/deleteUser/:username', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
app.get('/api/getLogs', async (req, res) => {
|
app.get('/api/getLogs', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
// Query the database to fetch logs using Sequelize model
|
// Query the database to fetch logs using Sequelize model
|
||||||
@ -814,11 +690,6 @@ app.get("/locations", isAuthenticated, async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const locationValidation = [
|
|
||||||
body('name').trim().isLength({ min: 1 }).withMessage('Name must not be empty').escape(),
|
|
||||||
body('added_by').trim().isLength({ min: 1 }).withMessage('Added by must not be empty').escape(),
|
|
||||||
body('description').trim().escape(),
|
|
||||||
];
|
|
||||||
app.post('/location/new', locationValidation, async (req, res) => {
|
app.post('/location/new', locationValidation, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const errors = validationResult(req);
|
const errors = validationResult(req);
|
||||||
@ -846,12 +717,6 @@ app.get("/locations", isAuthenticated, async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const locationValidationUpdate = [
|
|
||||||
body('id').trim().escape(),
|
|
||||||
body('name').trim().isLength({ min: 1 }).withMessage('Name must not be empty').escape(),
|
|
||||||
body('added_by').trim().isLength({ min: 1 }).withMessage('Added by must not be empty').escape(),
|
|
||||||
body('description').trim().escape(),
|
|
||||||
];
|
|
||||||
app.post('/location/update', locationValidationUpdate, async (req, res) => {
|
app.post('/location/update', locationValidationUpdate, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const errors = validationResult(req);
|
const errors = validationResult(req);
|
||||||
@ -880,6 +745,33 @@ app.get("/locations", isAuthenticated, async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
app.post('location/delete',locationdeleteValidation, async (req, res) => {
|
||||||
|
try {
|
||||||
|
const errors = validationResult(req);
|
||||||
|
if (!errors.isEmpty()) {
|
||||||
|
return res.status(400).json({ errors: errors.array() });
|
||||||
|
}
|
||||||
|
const sessionTokencookie = req.cookies['sessionToken'];
|
||||||
|
const user = await User.findOne({ where: { sessionid: sessionTokencookie } });
|
||||||
|
if (!user) {
|
||||||
|
return res.status(403).json({ error: 'Invalid sessionToken' });
|
||||||
|
}
|
||||||
|
const submittedCSRFToken = req.body.csrf_token;
|
||||||
|
if (!csrfTokenSession || submittedCSRFToken !== csrfTokenSession) {
|
||||||
|
return res.status(403).json({ error: 'CSRF token mismatch' });
|
||||||
|
}
|
||||||
|
const {id} = req.body;
|
||||||
|
const preparedData = {id};
|
||||||
|
// Make a POST request with the sanitized data using Axios
|
||||||
|
const axiosResponse = await axios.post(process.env.API_DELLOCATION, preparedData);
|
||||||
|
// Send the Axios response back to the client
|
||||||
|
res.status(axiosResponse.status).json(axiosResponse.data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error handling new sensor submission:', error);
|
||||||
|
res.status(500).json({ message: 'Internal Server Error' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
app.get("/sensors", isAuthenticated, async (req, res) => {
|
app.get("/sensors", isAuthenticated, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
// Render the inusers page with JSON data
|
// Render the inusers page with JSON data
|
||||||
@ -894,21 +786,34 @@ app.get("/sensors", isAuthenticated, async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const sensorValidation = [
|
|
||||||
body('id').trim().escape(),
|
|
||||||
body('sensorname').trim().isLength({ min: 1 }).withMessage('Sensor Name must not be empty').escape(),
|
|
||||||
body('added_by').trim().isLength({ min: 1 }).withMessage('Added by must not be empty').escape(),
|
|
||||||
body('macAddress').custom(value => {
|
|
||||||
const macAddressRegex = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/;
|
|
||||||
if (!macAddressRegex.test(value)) {
|
|
||||||
throw new Error('Invalid MAC address format');
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}).withMessage('Invalid MAC address format').escape(),
|
|
||||||
body('description').trim().escape(),
|
|
||||||
body('location').trim().escape()
|
|
||||||
];
|
|
||||||
app.post('sensor/new',sensorValidation, async (req, res) => {
|
app.post('sensor/new',sensorValidation, async (req, res) => {
|
||||||
|
try {
|
||||||
|
const errors = validationResult(req);
|
||||||
|
if (!errors.isEmpty()) {
|
||||||
|
return res.status(400).json({ errors: errors.array() });
|
||||||
|
}
|
||||||
|
const sessionTokencookie = req.cookies['sessionToken'];
|
||||||
|
const user = await User.findOne({ where: { sessionid: sessionTokencookie } });
|
||||||
|
if (!user) {
|
||||||
|
return res.status(403).json({ error: 'Invalid sessionToken' });
|
||||||
|
}
|
||||||
|
const submittedCSRFToken = req.body.csrf_token;
|
||||||
|
if (!csrfTokenSession || submittedCSRFToken !== csrfTokenSession) {
|
||||||
|
return res.status(403).json({ error: 'CSRF token mismatch' });
|
||||||
|
}
|
||||||
|
const { sensorname, added_by, macAddress, description, location} = req.body;
|
||||||
|
const preparedData = {sensorname, added_by, macAddress, description, location};
|
||||||
|
// Make a POST request with the sanitized data using Axios
|
||||||
|
const axiosResponse = await axios.post(process.env.API_NEWSENSOR, preparedData);
|
||||||
|
// Send the Axios response back to the client
|
||||||
|
res.status(axiosResponse.status).json(axiosResponse.data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error handling new sensor submission:', error);
|
||||||
|
res.status(500).json({ message: 'Internal Server Error' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('sensor/update',sensorupdateValidation, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const errors = validationResult(req);
|
const errors = validationResult(req);
|
||||||
if (!errors.isEmpty()) {
|
if (!errors.isEmpty()) {
|
||||||
@ -935,6 +840,33 @@ const sensorValidation = [
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.post('sensor/delete',sensordeleteValidation, async (req, res) => {
|
||||||
|
try {
|
||||||
|
const errors = validationResult(req);
|
||||||
|
if (!errors.isEmpty()) {
|
||||||
|
return res.status(400).json({ errors: errors.array() });
|
||||||
|
}
|
||||||
|
const sessionTokencookie = req.cookies['sessionToken'];
|
||||||
|
const user = await User.findOne({ where: { sessionid: sessionTokencookie } });
|
||||||
|
if (!user) {
|
||||||
|
return res.status(403).json({ error: 'Invalid sessionToken' });
|
||||||
|
}
|
||||||
|
const submittedCSRFToken = req.body.csrf_token;
|
||||||
|
if (!csrfTokenSession || submittedCSRFToken !== csrfTokenSession) {
|
||||||
|
return res.status(403).json({ error: 'CSRF token mismatch' });
|
||||||
|
}
|
||||||
|
const {id} = req.body;
|
||||||
|
const preparedData = {id};
|
||||||
|
// Make a POST request with the sanitized data using Axios
|
||||||
|
const axiosResponse = await axios.post(process.env.API_DELSENSOR, preparedData);
|
||||||
|
// Send the Axios response back to the client
|
||||||
|
res.status(axiosResponse.status).json(axiosResponse.data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error handling new sensor submission:', error);
|
||||||
|
res.status(500).json({ message: 'Internal Server Error' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
app.use(express.static("views"));
|
app.use(express.static("views"));
|
||||||
|
|
||||||
app.listen(PORT, () => {
|
app.listen(PORT, () => {
|
||||||
|
@ -3,19 +3,26 @@ $(document).ready(function () {
|
|||||||
$('#locationContainer').show();
|
$('#locationContainer').show();
|
||||||
$('#createLocationForm').hide();
|
$('#createLocationForm').hide();
|
||||||
$('#updateLocationForm').hide();
|
$('#updateLocationForm').hide();
|
||||||
|
$('#deleteLocationForm').hide();
|
||||||
});
|
});
|
||||||
$('#addLocationLink').on('click', function () {
|
$('#addLocationLink').on('click', function () {
|
||||||
$('#locationContainer').hide();
|
$('#locationContainer').hide();
|
||||||
$('#createLocationForm').show();
|
$('#createLocationForm').show();
|
||||||
$('#updateLocationForm').hide();
|
$('#updateLocationForm').hide();
|
||||||
|
$('#deleteLocationForm').hide();
|
||||||
});
|
});
|
||||||
$('#updateLocationLink').on('click', function () {
|
$('#updateLocationLink').on('click', function () {
|
||||||
$('#locationContainer').hide();
|
$('#locationContainer').hide();
|
||||||
$('#createLocationForm').hide();
|
$('#createLocationForm').hide();
|
||||||
$('#updateLocationForm').show();
|
$('#updateLocationForm').show();
|
||||||
populateLocationDropdown();
|
$('#deleteLocationForm').hide();
|
||||||
|
});
|
||||||
|
$('#deleteLocationLink').on('click', function () {
|
||||||
|
$('#locationContainer').hide();
|
||||||
|
$('#createLocationForm').hide();
|
||||||
|
$('#updateLocationForm').show();
|
||||||
|
$('#deleteLocationForm').show();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let locationArray = [];
|
let locationArray = [];
|
||||||
@ -42,8 +49,7 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
populateTableAndArray(locationsData);
|
populateTableAndArray(locationsData);
|
||||||
console.log(locationArray);
|
populateLocationDropdown();
|
||||||
|
|
||||||
$('#locationForm').on('submit', function (e) {
|
$('#locationForm').on('submit', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
@ -136,3 +142,39 @@ $('#locationForm').on('submit', function (e) {
|
|||||||
// Handle error as needed
|
// Handle error as needed
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#deleteForm').on('submit', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const selectedLocationId = $('#locationDropdown').val();
|
||||||
|
const csrf_token = $('#userForm input[name="csrf_token"]').val();
|
||||||
|
|
||||||
|
fetch('/location/delete', {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
id:selectedLocationId,
|
||||||
|
csrf_token: csrf_token
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
// Status 201 indicates successful creation
|
||||||
|
return response.json();
|
||||||
|
} else {
|
||||||
|
return response.json().then(data => {
|
||||||
|
throw new Error(data.message || `HTTP error! Status: ${response.status}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
console.log(`Location deleted successfully. Message: ${data.message}`);
|
||||||
|
alert('Location deleted successfully!');
|
||||||
|
resetFormFields();
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Location not deleted successfully', error);
|
||||||
|
// Handle error as needed
|
||||||
|
});
|
||||||
|
});
|
@ -62,9 +62,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="updateLocationForm" class="location-update-container" style="display: none;">
|
<div id="updateLocationForm" class="location-update-container" style="display: none;">
|
||||||
<h3>Add Location</h3>
|
<h3>Update Location</h3>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<form action="/api/v0/location/update" id="updateForm" method="put">
|
<form action="/location/update" id="updateForm" method="put">
|
||||||
<div class="Location-details">
|
<div class="Location-details">
|
||||||
<div class="input-box">
|
<div class="input-box">
|
||||||
<span class="details">Location to Update</span>
|
<span class="details">Location to Update</span>
|
||||||
@ -87,6 +87,25 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="deleteLocationForm" class="location-delete-container" style="display: none;">
|
||||||
|
<h3>Delete Location</h3>
|
||||||
|
<div class="content">
|
||||||
|
<form action="/location/delete" id="deleteForm" method="delete">
|
||||||
|
<div class="Location-details">
|
||||||
|
<div class="input-box">
|
||||||
|
<span class="details">Location to Delete</span>
|
||||||
|
<select name="location" id="locationDropdown" required>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" name="csrf_token" value="<%= csrfToken %>">
|
||||||
|
<div class="button">
|
||||||
|
<input type="submit" value="submit">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
Any Issue faced, Please contact the administrator at 11111111 or ecosaverAdmin@gmail.com
|
Any Issue faced, Please contact the administrator at 11111111 or ecosaverAdmin@gmail.com
|
||||||
</footer>
|
</footer>
|
||||||
|
@ -3,12 +3,32 @@ $(document).ready(function () {
|
|||||||
$('#sensorContainer').show();
|
$('#sensorContainer').show();
|
||||||
$('#createSensorForm').hide();
|
$('#createSensorForm').hide();
|
||||||
$('#additional-text4').hide();
|
$('#additional-text4').hide();
|
||||||
|
$('#updateSensorForm').hide();
|
||||||
|
$('#deleteSensorForm').hide();
|
||||||
});
|
});
|
||||||
$('#addSensorLink').on('click', function () {
|
$('#addSensorLink').on('click', function () {
|
||||||
$('#sensorContainer').hide();
|
$('#sensorContainer').hide();
|
||||||
$('#createSensorForm').show();
|
$('#createSensorForm').show();
|
||||||
$('#additional-text4').show();
|
$('#additional-text4').show();
|
||||||
|
$('#updateSensorForm').hide();
|
||||||
|
$('#deleteSensorForm').hide();
|
||||||
});
|
});
|
||||||
|
$('#updateSensorLink').on('click', function () {
|
||||||
|
$('#sensorContainer').hide();
|
||||||
|
$('#createSensorForm').show();
|
||||||
|
$('#additional-text4').show();
|
||||||
|
$('#updateSensorForm').show();
|
||||||
|
$('#deleteSensorForm').hide();
|
||||||
|
});
|
||||||
|
$('#deleteSensorLink').on('click', function () {
|
||||||
|
$('#sensorContainer').hide();
|
||||||
|
$('#createSensorForm').show();
|
||||||
|
$('#additional-text4').show();
|
||||||
|
$('#updateSensorForm').hide();
|
||||||
|
$('#deleteSensorForm').show();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
function populateTableAndArray(data, locationsArray) {
|
function populateTableAndArray(data, locationsArray) {
|
||||||
const tableBody = document.getElementById("sensorTableBody");
|
const tableBody = document.getElementById("sensorTableBody");
|
||||||
@ -38,16 +58,13 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
function populateLocationDropdown() {
|
function populateLocationDropdown() {
|
||||||
const locationDropdown = document.getElementById('locationDropdown');
|
const locationDropdown = document.getElementById('locationDropdown');
|
||||||
|
|
||||||
// Clear existing options
|
// Clear existing options
|
||||||
locationDropdown.innerHTML = '';
|
locationDropdown.innerHTML = '';
|
||||||
|
|
||||||
// Add a default option
|
// Add a default option
|
||||||
const defaultOption = document.createElement('option');
|
const defaultOption = document.createElement('option');
|
||||||
defaultOption.text = 'Select a Location';
|
defaultOption.text = 'Select a Location';
|
||||||
defaultOption.value = '';
|
defaultOption.value = '';
|
||||||
locationDropdown.add(defaultOption);
|
locationDropdown.add(defaultOption);
|
||||||
|
|
||||||
// Add locations as options
|
// Add locations as options
|
||||||
locationsArray.forEach(location => {
|
locationsArray.forEach(location => {
|
||||||
const option = document.createElement('option');
|
const option = document.createElement('option');
|
||||||
@ -58,6 +75,29 @@ $(document).ready(function () {
|
|||||||
}
|
}
|
||||||
populateLocationDropdown();
|
populateLocationDropdown();
|
||||||
|
|
||||||
|
function populateSensorDropdown() {
|
||||||
|
const sensorDropdown = document.getElementById('sensorDropdown');
|
||||||
|
|
||||||
|
// Clear existing options
|
||||||
|
sensorDropdown.innerHTML = '';
|
||||||
|
|
||||||
|
// Add a default option
|
||||||
|
const defaultOption = document.createElement('option');
|
||||||
|
defaultOption.text = 'Select a Sensor';
|
||||||
|
defaultOption.value = '';
|
||||||
|
sensorDropdown.add(defaultOption);
|
||||||
|
|
||||||
|
// Add locations as options
|
||||||
|
sensorArray.forEach(location => {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.text = sensor.sensorname;
|
||||||
|
option.value = sensor.id;
|
||||||
|
sensorDropdown.add(option);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
populateSensorDropdown();
|
||||||
|
|
||||||
|
|
||||||
$('#sensorForm').on('submit', function (e) {
|
$('#sensorForm').on('submit', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const sensor = $('#sensor').val();
|
const sensor = $('#sensor').val();
|
||||||
@ -73,7 +113,6 @@ $('#sensorForm').on('submit', function (e) {
|
|||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
id: id,
|
|
||||||
sensorname: sensor,
|
sensorname: sensor,
|
||||||
added_by: user,
|
added_by: user,
|
||||||
mac_address: macAddress,
|
mac_address: macAddress,
|
||||||
@ -102,3 +141,85 @@ $('#sensorForm').on('submit', function (e) {
|
|||||||
// Handle error as needed
|
// Handle error as needed
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#updatesensorForm').on('submit', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const id = $('#sensorDropdown').val();
|
||||||
|
const sensorname = $('#sensorname').val();
|
||||||
|
const user = req.session.jobTitle;
|
||||||
|
const macAddress = $('#macAddress').val();
|
||||||
|
const description = $('#description').val();
|
||||||
|
const location = $('#locationDropdown').val();
|
||||||
|
const csrf_token = $('#userForm input[name="csrf_token"]').val();
|
||||||
|
|
||||||
|
fetch('sensor/update', {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
id: id,
|
||||||
|
sensorname: sensorname,
|
||||||
|
added_by: user,
|
||||||
|
mac_address: macAddress,
|
||||||
|
description: description,
|
||||||
|
location: location,
|
||||||
|
csrf_token: csrf_token
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
// Status 201 indicates successful creation
|
||||||
|
return response.json();
|
||||||
|
} else {
|
||||||
|
return response.json().then(data => {
|
||||||
|
throw new Error(data.message || `HTTP error! Status: ${response.status}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
console.log(`Sensor updated successfully. Message: ${data.message}`);
|
||||||
|
alert('Sensor updated successfully!');
|
||||||
|
resetFormFields();
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Sensor not updated successfully', error);
|
||||||
|
// Handle error as needed
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#deleteForm').on('submit', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const selectedSensorId = $('#sensorDropdown').val();
|
||||||
|
const csrf_token = $('#userForm input[name="csrf_token"]').val();
|
||||||
|
|
||||||
|
fetch('/sensor/delete', {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
id:selectedSensorId,
|
||||||
|
csrf_token: csrf_token
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
// Status 201 indicates successful creation
|
||||||
|
return response.json();
|
||||||
|
} else {
|
||||||
|
return response.json().then(data => {
|
||||||
|
throw new Error(data.message || `HTTP error! Status: ${response.status}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
console.log(`Sensor deleted successfully. Message: ${data.message}`);
|
||||||
|
alert('Sensor deleted successfully!');
|
||||||
|
resetFormFields();
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Sensor not deleted successfully', error);
|
||||||
|
// Handle error as needed
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -20,8 +20,8 @@
|
|||||||
<nav>
|
<nav>
|
||||||
<a href="#" id="allSensorLink">All Sensor</a>
|
<a href="#" id="allSensorLink">All Sensor</a>
|
||||||
<a href="#" id="addSensorLink">Add Sensor</a>
|
<a href="#" id="addSensorLink">Add Sensor</a>
|
||||||
<a href="#">Update Sensor</a>
|
<a href="#" id="updateSensorLink">Update Sensor</a>
|
||||||
<a href="#">Delete Sensor</a>
|
<a href="#" id="deleteSensorLink">Delete Sensor</a>
|
||||||
<a href="/home" id="homeLink">Home</a>
|
<a href="/home" id="homeLink">Home</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
@ -83,13 +83,68 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="updateSensorForm" class="sensor-update-container" style="display: none;">
|
||||||
|
<h3>Add Location</h3>
|
||||||
|
<div class="content">
|
||||||
|
<form action="/sensor/update" id="updateForm" method="put">
|
||||||
|
<div class="Location-details">
|
||||||
|
<div class="input-box">
|
||||||
|
<span class="details">Sensor to Update</span>
|
||||||
|
<select name="Sensor" id="sensorDropdown" required>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="input-box">
|
||||||
|
<span class="details">Sensor Name</span>
|
||||||
|
<input type="text" name="sensorname" id="sensorname" placeholder="Enter Sensor name" required>
|
||||||
|
</div>
|
||||||
|
<div class="input-box">
|
||||||
|
<span class="details">Mac Address</span>
|
||||||
|
<input type="text" name="macAddress" id="macAddress" placeholder="Enter the Mac Address" required>
|
||||||
|
</div>
|
||||||
|
<div class="input-box">
|
||||||
|
<span class="details">Description</span>
|
||||||
|
<input type="text" name="description" id="description" placeholder="Enter the description here" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="input-box">
|
||||||
|
<span class="details">Location</span>
|
||||||
|
<select name="location" id="locationDropdown" required>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" name="csrf_token" value="<%= csrfToken %>">
|
||||||
|
<input type="hidden" name="csrf_token" value="<%= csrfToken %>">
|
||||||
|
<div class="button">
|
||||||
|
<input type="submit" value="submit">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="deleteSensorForm" class="sensor-delete-container" style="display: none;">
|
||||||
|
<h3>Delete Location</h3>
|
||||||
|
<div class="content">
|
||||||
|
<form action="/sensor/delete" id="deleteForm" method="delete">
|
||||||
|
<div class="Location-details">
|
||||||
|
<div class="input-box">
|
||||||
|
<span class="details">Sensor to Delete</span>
|
||||||
|
<select name="sensor" id="sensorDropdown" required>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" name="csrf_token" value="<%= csrfToken %>">
|
||||||
|
<div class="button">
|
||||||
|
<input type="submit" value="submit">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
Any Issue faced, Please contact the administrator at 11111111 or ecosaverAdmin@gmail.com
|
Any Issue faced, Please contact the administrator at 11111111 or ecosaverAdmin@gmail.com
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
<script>
|
<script>
|
||||||
const locationsArray = <%=-JSON.stringify(locationsData) %>;
|
const locationsArray = <%-JSON.stringify(locationsData) %>;
|
||||||
const sensorArray = <%- JSON.stringify(sensorData) %>;
|
const sensorArray = <%- JSON.stringify(sensorData) %>;
|
||||||
</script>
|
</script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/2.3.3/purify.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/2.3.3/purify.min.js"></script>
|
||||||
|
5
package-lock.json
generated
5
package-lock.json
generated
@ -1626,6 +1626,11 @@
|
|||||||
"formdata-polyfill": "^4.0.10"
|
"formdata-polyfill": "^4.0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nodemailer": {
|
||||||
|
"version": "6.9.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.8.tgz",
|
||||||
|
"integrity": "sha512-cfrYUk16e67Ks051i4CntM9kshRYei1/o/Gi8K1d+R34OIs21xdFnW7Pt7EucmVKA0LKtqUGNcjMZ7ehjl49mQ=="
|
||||||
|
},
|
||||||
"nopt": {
|
"nopt": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user