sensor and location done and some cleanupd

testing will be required
This commit is contained in:
BIG2EYEZ 2024-01-24 15:04:50 +08:00
parent 940d40ed38
commit 5c3a43ddd6
9 changed files with 490 additions and 188 deletions

42
Sean/modules/otpUtils.js Normal file
View 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
};

View 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;

View 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
};

View File

@ -1,21 +1,23 @@
const express = require("express");
const session = require("express-session");
const rateLimit = require('express-rate-limit');
const cookieParser = require('cookie-parser');
const bodyParser = require("body-parser");
const bcrypt = require("bcrypt");
const crypto = require("crypto");
const nodemailer = require("nodemailer");
const otpGenerator = require('otp-generator');
const { body, validationResult } = require('express-validator');
const validator = require('validator');
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 { Sequelize } = require('sequelize');
const { transporter } = require("./modules/nodeMailer");
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();
app.use(bodyParser.urlencoded({ extended: true }));
@ -28,7 +30,6 @@ app.use(bodyParser.urlencoded({ extended: true }));
app.set("view engine", "ejs");
app.use(session({
secret: process.env.key,
resave: false,
@ -46,76 +47,27 @@ function isAuthenticated(req, res, next) {
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) => {
res.render("login", { error: null });
});
const limiter = 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.use('/login', rateLimit);
app.post('/login', loginValidation, async (req, res) => {
try {const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.render('login', { error: 'Invalid input. Please check your credentials.', csrfToken: req.session.csrfToken });
}
let { username, password } = req.body;
username = username.trim();
const user = await User.findOne({ where: { username } });
if (user) {
const isLoginSuccessful = await bcrypt.compare(password, user.password);
if (isLoginSuccessful) {
await userLogs.create({ username, success: true, activity: "Credentials entered correctly" });
const { otp, expirationTime } = generateOTP();
req.session.otp = otp;
@ -161,17 +113,12 @@ async (req, res) => {
// OTP verification route
app.post("/verify-otp", [
body('otp').escape().trim().isLength({ min: 1 }).withMessage('OTP must not be empty'),
],
async (req, res) => {
app.post("/verify-otp", otpValidation ,async (req, res) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.render('otp', { error: 'Invalid OTP. Please try again.'});
}
const enteredOTP = req.body.otp;
if (!req.session) {
@ -209,17 +156,10 @@ app.post("/verify-otp", [
req.session.authenticated = true;
req.session.username = req.body.username;
req.session.sessionToken = sessionToken;
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
console.log(`Generated Session Token: ${sessionToken}`);
res.redirect("/home");
} else {
if (req.body.username) {
@ -262,17 +202,14 @@ app.post("/verify-otp", [
}
});
app.get("/home", isAuthenticated, async (req, res) => {
app.get("/home", isAuthenticated, (req, res) => {
// Render the home page with sensor data
res.render("home", {
username: req.session.username,
});
const response = await axios.get(process.env.API_ALLLOCATION);
const valueData = response.data;
console.log = (valueData);
res.render("home", { username: req.session.username, valueData});
});
app.get("/inusers", isAuthenticated, async (req, res) => {
try {
// Fetch all user data from the database using Sequelize
@ -318,20 +255,8 @@ function isStrongPassword(password) {
return true;
}
app.post(
'/createUser',
[
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) => {
'/createUser', createValidation, async (req, res) => {
try {
const errors = validationResult(req);
@ -463,24 +388,13 @@ app.post("/forgot-password", async (req, res) => {
const error = "Username or email not found.";
return res.render("forgot-password", { error, success: null });
}
// Generate reset token and update the user
const reset_token = crypto.randomBytes(20).toString("hex");
const reset_token_expiry = new Date(Date.now() + 3600000); // Token expires in 1 hour
// Update the user with the reset token and expiry
await User.update(
{
reset_token,
reset_token_expiry,
},
{
where: {
id: user.id, // Replace 'id' with the actual primary key field of your User model
},
}
await User.update({reset_token,reset_token_expiry,},
{where: {id: user.id},}
);
// Send email with reset link
const resetLink = `http://localhost:3000/reset-password/${reset_token}`;
const mailOptions = {
@ -488,12 +402,9 @@ app.post("/forgot-password", async (req, res) => {
subject: "Password Reset",
text: `Click on the following link to reset your password: ${resetLink}`,
};
await transporter.sendMail(mailOptions);
const success = "Password reset email sent successfully. Check your inbox.";
res.render("forgot-password", { error: null, success });
// Log the successful sending of the reset link in the database
await userLogs.create({
username: user.username,
@ -509,29 +420,22 @@ app.post("/forgot-password", async (req, res) => {
console.error("Error during password reset:", error);
const errorMessage = "An error occurred during the password reset process.";
res.render("forgot-password", { error: errorMessage, success: null });
}
});
}});
app.post("/reset-password/:token", async (req, res) => {
try {
const { token } = req.params;
const { password, confirmPassword } = req.body;
// Sanitize the inputs
const sanitizedToken = validator.escape(token);
const sanitizedPassword = validator.escape(password);
const sanitizedConfirmPassword = validator.escape(confirmPassword);
// Find user with matching reset token and not expired
const user = await User.findOne({
where: {
reset_token: sanitizedToken,
reset_token_expiry: { [Sequelize.Op.gt]: new Date() },
where: {reset_token: sanitizedToken,
reset_token_expiry: { [Sequelize.Op.gt]: new Date() },
},
});
if (!user) {
// Pass the error to the template when rendering the reset-password page
return res.render("reset-password", {
@ -539,7 +443,6 @@ app.post("/forgot-password", async (req, res) => {
resetError: "Invalid or expired reset token",
});
}
// Check if passwords match
if (sanitizedPassword !== sanitizedConfirmPassword) {
// 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",
});
}
// Check if the new password meets complexity requirements
if (!isStrongPassword(sanitizedPassword)) {
// Pass the error to the template when rendering the reset-password page
return res.render("reset-password", {
token,
resetError:
token, 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.",
});
}
// Hash the new password
const saltRounds = 10;
const hashedPassword = await bcrypt.hash(sanitizedPassword, saltRounds);
// Update user's password and clear reset token
const updateQuery = {
password: hashedPassword,
reset_token: null,
reset_token_expiry: null,
};
const whereCondition = {
reset_token: sanitizedToken,
};
const whereCondition = {reset_token: sanitizedToken,};
await User.update(updateQuery, {
where: whereCondition,
});
@ -619,10 +515,8 @@ app.post("/reset-password", async (req, res) => {
return res.status(403).json({ error: 'CSRF token mismatch' });
}
const sessionTokencookie = req.cookies['sessionToken'];
// Verify sessionToken with the one stored in the database
const user = await User.findOne({ where: { sessionid: sessionTokencookie } });
if (!user) {
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 sanitizedPassword = validator.escape(password);
const sanitizedConfirmPassword = validator.escape(confirmPassword);
// Check if passwords match
if (sanitizedPassword !== sanitizedConfirmPassword) {
return res.status(400).json({ error: "Passwords do not match" });
}
// Check if the new password meets complexity requirements
if (!isStrongPassword(sanitizedPassword)) {
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.",
});
}
try {
// Find the user in the database
const user = await User.findOne({ where: { username: sanitizedUsername } });
if (!user) {
return res.status(404).json({ error: "User does not exist" });
}
// Generate a random salt and hash the new password
const saltRounds = 10;
const hashedPassword = await bcrypt.hash(sanitizedPassword, saltRounds);
// Update user's password
await User.update(
{ password: hashedPassword },
{ where: { username: sanitizedUsername } }
);
// Log password reset activity
await userLogs.create({
username: creatorUsername,
activity: `Password has been reset for ${sanitizedUsername}`,
});
// Password update successful
return res.status(200).json({ success: "Password updated successfully" });
} catch (error) {
@ -679,10 +565,8 @@ app.post("/reset-password", async (req, res) => {
app.get('/searchUser', async (req, res) => {
const { username } = req.query;
// Sanitize the input
const sanitizedUsername = validator.escape(username);
try {
// Find the user in the database
const user = await User.findOne({ where: { username: sanitizedUsername } });
@ -690,11 +574,7 @@ app.get('/searchUser', async (req, res) => {
if (!user) {
// No user found with the given username
res.status(404).json({ success: false, error: 'User not found' });
} else {
// User found, return user data
res.json(user);
}
} else {res.json(user)}
} catch (error) {
console.error('Sequelize query error:', error);
res.status(500).json({ success: false, error: 'Internal Server Error' });
@ -705,7 +585,6 @@ app.get('/api/users', async (req, res) => {
try {
// Find all users in the database
const users = await User.findAll();
// Return the users in the response
res.json(users);
} catch (error) {
@ -774,9 +653,6 @@ app.delete('/api/deleteUser/:username', async (req, res) => {
}
});
app.get('/api/getLogs', async (req, res) => {
try {
// 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) => {
try {
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) => {
try {
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) => {
try {
// 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) => {
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 {
const errors = validationResult(req);
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.listen(PORT, () => {

View File

@ -3,19 +3,26 @@ $(document).ready(function () {
$('#locationContainer').show();
$('#createLocationForm').hide();
$('#updateLocationForm').hide();
$('#deleteLocationForm').hide();
});
$('#addLocationLink').on('click', function () {
$('#locationContainer').hide();
$('#createLocationForm').show();
$('#updateLocationForm').hide();
$('#deleteLocationForm').hide();
});
$('#updateLocationLink').on('click', function () {
$('#locationContainer').hide();
$('#createLocationForm').hide();
$('#updateLocationForm').show();
populateLocationDropdown();
$('#deleteLocationForm').hide();
});
$('#deleteLocationLink').on('click', function () {
$('#locationContainer').hide();
$('#createLocationForm').hide();
$('#updateLocationForm').show();
$('#deleteLocationForm').show();
});
});
let locationArray = [];
@ -42,8 +49,7 @@ $(document).ready(function () {
});
}
populateTableAndArray(locationsData);
console.log(locationArray);
populateLocationDropdown();
$('#locationForm').on('submit', function (e) {
e.preventDefault();
@ -136,3 +142,39 @@ $('#locationForm').on('submit', function (e) {
// 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
});
});

View File

@ -62,9 +62,9 @@
</div>
<div id="updateLocationForm" class="location-update-container" style="display: none;">
<h3>Add Location</h3>
<h3>Update Location</h3>
<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="input-box">
<span class="details">Location to Update</span>
@ -87,6 +87,25 @@
</form>
</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>
Any Issue faced, Please contact the administrator at 11111111 or ecosaverAdmin@gmail.com
</footer>

View File

@ -3,12 +3,32 @@ $(document).ready(function () {
$('#sensorContainer').show();
$('#createSensorForm').hide();
$('#additional-text4').hide();
$('#updateSensorForm').hide();
$('#deleteSensorForm').hide();
});
$('#addSensorLink').on('click', function () {
$('#sensorContainer').hide();
$('#createSensorForm').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) {
const tableBody = document.getElementById("sensorTableBody");
@ -38,16 +58,13 @@ $(document).ready(function () {
function populateLocationDropdown() {
const locationDropdown = document.getElementById('locationDropdown');
// Clear existing options
locationDropdown.innerHTML = '';
// Add a default option
const defaultOption = document.createElement('option');
defaultOption.text = 'Select a Location';
defaultOption.value = '';
locationDropdown.add(defaultOption);
// Add locations as options
locationsArray.forEach(location => {
const option = document.createElement('option');
@ -58,6 +75,29 @@ $(document).ready(function () {
}
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) {
e.preventDefault();
const sensor = $('#sensor').val();
@ -73,7 +113,6 @@ $('#sensorForm').on('submit', function (e) {
'Content-Type': 'application/json'
},
body: JSON.stringify({
id: id,
sensorname: sensor,
added_by: user,
mac_address: macAddress,
@ -102,3 +141,85 @@ $('#sensorForm').on('submit', function (e) {
// 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
});
});

View File

@ -20,8 +20,8 @@
<nav>
<a href="#" id="allSensorLink">All Sensor</a>
<a href="#" id="addSensorLink">Add Sensor</a>
<a href="#">Update Sensor</a>
<a href="#">Delete Sensor</a>
<a href="#" id="updateSensorLink">Update Sensor</a>
<a href="#" id="deleteSensorLink">Delete Sensor</a>
<a href="/home" id="homeLink">Home</a>
</nav>
@ -83,13 +83,68 @@
</ul>
</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>
Any Issue faced, Please contact the administrator at 11111111 or ecosaverAdmin@gmail.com
</footer>
</body>
<script>
const locationsArray = <%=-JSON.stringify(locationsData) %>;
const locationsArray = <%-JSON.stringify(locationsData) %>;
const sensorArray = <%- JSON.stringify(sensorData) %>;
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/2.3.3/purify.min.js"></script>

5
package-lock.json generated
View File

@ -1626,6 +1626,11 @@
"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": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",