Update CSS, add relationship between sensorModel and locationModel, and remove console.log statements

This commit is contained in:
newtbot 2024-01-26 04:07:11 +08:00
parent ba498a4d4b
commit d38423fa6d
19 changed files with 213 additions and 205 deletions

View File

@ -9,13 +9,13 @@ const sequelize = new Sequelize(
process.env.DB_USER,
process.env.DB_PASS,
{
host: "mpsqldatabase.mysql.database.azure.com",
host: "mpsqldatabasean.mysql.database.azure.com",
dialect: 'mysql',
// attributeBehavior?: 'escape' | 'throw' | 'unsafe-legacy';
attributeBehavior: 'escape',
dialectOptions: {
ssl: {
ca: fs.readFileSync(path.resolve(__dirname, '../cert/DigiCertGlobalRootCA.crt.pem')),
ca: fs.readFileSync(path.resolve(__dirname, '../cert/DigiCertGlobalRootCA.crt_3.pem')),
},
},

2
api.MD
View File

@ -172,4 +172,4 @@ http://localhost/api/v0/sensor-data/data?week=1&sensorid=1&locationid=1&page=2&p
curl localhost/api/v0/user/register -H "Content-Type: application/json" -X POST -d '{"username": "testuser123", "password": "thisisthesystemuserpasswordnoob", "email": "testuser123@ecosaver.com", "address": "Nanyang Polytechnic 180 Ang Mo Kio Avenue 8 Singapore 569830", "phone": "12345678"}'
curl localhost:3000/api/v0/token/new -H "Content-Type: application/json" -X POST -d '{"userid": "5", "permission": "canRead"}'
curl localhost/api/v0/token/new -H "Content-Type: application/json" -X POST -d '{"userid": "5", "permission": "canRead"}'

View File

@ -51,26 +51,16 @@ app.use("/", require("./routes/render"));
// used, this is what will be called.
app.use(function (req, res, next) {
//application/json; charset=utf-8
if (req.is("application/json" || "application/json; charset=utf-8")) {
var err = new Error("Not Found");
err.message = "Page not found";
err.status = 404;
next(err);
} else {
res.status(404).render("404");
}
});
// Error handler. This is where `next()` will go on error
app.use(function (err, req, res, next) {
console.error(err.status || res.status, err.name, req.method, req.url);
if (![404].includes(err.status || res.status)) {
console.error(err.message);
console.error(err.stack);
console.error("=========================================");
}
console.log(err.name + " validation error");
// Parse key error for Sequilzw
let keyErrors = {};
if (["SequelizeValidationError"].includes(err.name) && err.errors) {
@ -82,17 +72,26 @@ app.use(function (err, req, res, next) {
res.status = 422;
}
if (![404, 422].includes(err.status || res.status)) {
if (![404, 401, 422].includes(err.status || res.status)) {
console.error(err.message);
console.error(err.stack);
console.error("=========================================");
}
res.status(err.status || 500);
// res.status(err.status || 500);
if (req.get('Content-Type') && req.get('Content-Type').includes("json")) {
res.json({
name: err.name || "Unknown error",
message: err.message,
keyErrors,
});
}
else {
res.json({
name: err.name || "Unknown error",
message: err.message,
keyErrors,
});
}
});

View File

@ -107,4 +107,6 @@ const sensorModel = sequelize.define(
}
);
sensorModel.belongsTo(locationModel);
module.exports = { sensorModel };

View File

@ -3,7 +3,7 @@ const { Sequelize, DataTypes } = require("sequelize");
const { sequelize } = require("../mySQL");
const { userModel } = require("./userModel");
//sequelize.sync();
sequelize.sync();
const tokenModel = sequelize.define(
"token",
{

View File

@ -9,13 +9,13 @@ const sequelize = new Sequelize(
process.env.DB_USER,
process.env.DB_PASS,
{
host: "mpsqldatabase.mysql.database.azure.com",
host: "mpsqldatabasean.mysql.database.azure.com",
dialect: 'mysql',
// attributeBehavior?: 'escape' | 'throw' | 'unsafe-legacy';
attributeBehavior: 'escape',
dialectOptions: {
ssl: {
ca: fs.readFileSync(path.resolve(__dirname, '../cert/DigiCertGlobalRootCA.crt.pem')),
ca: fs.readFileSync(path.resolve(__dirname, '../cert/DigiCertGlobalRootCA.crt_3.pem')),
},
},

View File

@ -1,19 +1,41 @@
const { hash, compareHash } = require("./bcrypt.js");
const { tokenModel } = require("../database/model/tokenModel.js");
const { userModel } = require("../database/model/userModel");
const { hash, compareHash } = require("./bcrypt.js");
const { generateUUID } = require("./generateUUID.js");
const { isValid } = require("./isValid");
async function getTokenByToken(token) {
const splitAuthToken = token.split("-");
const rowid = splitAuthToken[0];
const suppliedToken = splitAuthToken.slice(1).join("-");
token = await tokenModel.findByPk(rowid, { include: userModel });
token.isValid = await compareHash(suppliedToken, token.token); //true
console.log("function api getTokenByToken token", token.isValid);
token.isValid = token.isValid && isValid(token.expiration);
console.log("function api getTokenByToken token", token.isValid);
if (!token.isValid) {
//add boolean to token table
token.destroy();
}
/*
1) take userid
2) generate random api key
3) hash the api key
4) append userid with - and api key
5) you give the user rowid-uuidv4
6) store in database
console.log(
"function api getTokenByToken token",
await compareHash(suppliedToken, token.token),
isValid("token" , token.expiration)
);
*/
//can be used for api key or token. Both are the same logic
console.log(token.isValid);
return token;
}
async function addToken(userId, permission, expiry) {
let uuid = await generateUUID();
let hashtoken = await hash(uuid);
//console.log("user id", userId);
// return { token: token, userid: userRes.id, username: userRes.username };
// let token = await addToken(userRes.id , "canRead" , tokenToLive);
let token = await tokenModel.create({
userid: userId,
@ -26,23 +48,4 @@ async function addToken(userId, permission , expiry) {
return token.id + "-" + uuid;
}
async function checkToken(Supplied, rowid) {
try {
const retrivedToken = await tokenModel.findOne({
raw: true,
attributes: ["token", "permission"],
where: {
id: rowid,
},
});
//console.log(retrivedKey.apikey);
if (compareHash(Supplied, retrivedToken.token)) {
//return true;
return retrivedToken.permission;
}
} catch (error) {
console.error(error);
}
}
module.exports = { addToken , checkToken };
module.exports = { addToken, getTokenByToken };

View File

@ -1,20 +1,14 @@
const moment = require("moment");
const currentTime = moment().format("YYYY-MM-DD HH:mm:ss");
//time is taken from the token
function isValid(time) {
const timeDiff = moment(currentTime).diff(time, "minutes");
if (timeDiff > 1) {
console.log(timeDiff);
if (
Math.floor(new Date(time).getTime() / 1000) <
Math.floor(new Date().getTime() / 1000)
) {
return false;
}
return true;
}
module.exports = { isValid };

View File

@ -18,15 +18,19 @@ async function getSensorData() {
const sensorData = await sensorDataModel.findAll();
return sensorData;
}
let dataArray = [];
async function addSensorData(id_sensor, id_location, sensordata) {
const sensorData = await sensorDataModel.create({
sensorid: id_sensor,
locationid: id_location ,
measurement: sensordata,
measurement: sensordata.measurement,
});
io().emit('sensorData:new', sensorData)
//console.log("sensorData", sensorData);
//console.log("sensorData", sensordata);
dataArray.push(sensordata);
console.log("dataArray", dataArray);
io().emit('sensorData:new', dataArray)
return sensorData;
}
@ -61,6 +65,14 @@ async function getSensorDataById(id) {
});
return sensorData;
}
async function getLatestData() {
const sensorData = await sensorDataModel.findAll({
limit: 1,
order: [["createdAt", "DESC"]],
});
return sensorData;
}
var ormQuery = {};
var whereClause = {};
var whereDate = {};
@ -724,5 +736,6 @@ module.exports = {
getSensorDataById,
getData,
getDatabyRange,
getLatestData,
};

View File

@ -2,7 +2,6 @@ const { Op } = require('sequelize')
const { hash, compareHash } = require("./bcrypt.js");
const { addToken } = require("./api");
const { userModel } = require("../database/model/userModel");
moment = require('moment')
@ -71,9 +70,11 @@ async function loginUser(user) {
if (!match) return false;
//console.log('loginUser', userRes.id, userRes.username);
//generate token and permission and experiation time
const currentTime = moment().format('YYYY-MM-DD HH:mm:ss');
let token = await addToken(userRes.id , "canRead" , currentTime);
//generate token and permission and experiation time + 30 mins
//let tokenToLive = moment().add(30, 'minutes').format();
let currentDate = new Date();
let tokenToLive = new Date(currentDate.getTime() + 30 * 60000);
let token = await addToken(userRes.id , "canRead" , tokenToLive);
return { token: token, userid: userRes.id, username: userRes.username };
}

View File

@ -1,68 +1,36 @@
const { tokenModel } = require("../database/model/tokenModel");
const { userModel } = require("../database/model/userModel");
const { compareHash } = require("../functions/bcrypt");
const { checkToken } = require("../functions/api");
const { isValid } = require("../functions/isValid");
const { getTokenByToken } = require("../functions/api");
const permissionError = new Error('PermissionError')
permissionError.name = "Inadequate Permission Error"
permissionError.status = 401
permissionError.message = "Inadequate permission to complete this response"
async function auth(req, res, next) {
try {
const authToken = req.header("auth-token");
if (!authToken) {
const error = new Error("No Token key was supplied. Invalid request");
throw error;
const token = await getTokenByToken(req.header("auth-token"));
if (!token || !token.isValid){
throw permissionError;
}
const splitAuthToken = authToken.split("-");
const rowid = splitAuthToken[0];
const suppliedToken = splitAuthToken.slice(1).join("-");
const token = await tokenModel.findByPk(rowid, { include: userModel });
if (!token) {
const error = new Error("Token key not found. Invalid request");
throw error;
}
const isMatch = await compareHash(suppliedToken, token.token);
console.log(isMatch);
if (!isMatch) {
const error = new Error("Token key not found. Invalid request");
throw error;
}
//if token is a match
req.token = token;
req.user = await token.getUser();
const permission = await checkToken(suppliedToken, rowid);
const route = req.originalUrl.split("?")[0]; // Removing query parameters
//if route is from user/ and permission is canRead allow it to do CRUD
if (route.includes("/user/") && permission === "canRead") {
next();
if (route.includes("/user/") && token.permission === "canRead") {
return next();
}
if ((req.method === "GET" && permission === "canRead") || (["GET", "POST", "PUT", "DELETE"].includes(req.method) && permission === "canWrite")) {
next();
}
if (!isValid(token.expiration)){
req.token.destroy();
throw new Error("Token expired");
if ((req.method === "GET" && token.permission === "canRead") || (["GET", "POST", "PUT", "DELETE"].includes(req.method) && token.permission === "canWrite")) {
return next();
}
throw permissionError
} catch (error) {
next(error);
}
}
module.exports = { auth };
/*
else {
const error = new Error("Insufficient permission");
error.status = 401;
throw error;
}
*/

View File

@ -3812,6 +3812,7 @@
.card-text {
color: #000000;
font-size: 16px;
}
/* edit profile */

View File

@ -186,9 +186,7 @@ app.auth = (function (app) {
function isLoggedIn(callback) {
if (getToken()) {
console.log("you shldnt appear at all");
return app.api.get("user/me", function (error, data) {
console.log(error, data);
if (!error) app.auth.user = data;
return callback(error, data);
});

View File

@ -18,5 +18,8 @@ router.use('/sensor', [auth, APIlogger], require('./sensor.js'));
//sensor data route
router.use('/sensor-data', [auth, APIlogger], require('./sensorData.js'));
//latest sensor data to display on dashboard
router.use('/latest-sensor-data', [APIlogger], require('./latestsensorData.js'));
module.exports = router;

View File

@ -0,0 +1,21 @@
const {
getLatestData,
} = require("../functions/sensorData");
const express = require("express");
const router = express.Router();
router.get("/data", async (req, res, next) => {
try {
console.log(req.query);
const data = await getLatestData();
res.status(200).json(data);
} catch (error) {
console.error(error);
next(error);
}
});
module.exports = router;

View File

@ -8,7 +8,7 @@ const router = express.Router();
router.get("/me", async function (req, res, next) {
try {
let user = await getUserByID(req.user);
console.log(user);
//console.log(user);
res.json({
user: user,
});

View File

@ -1,9 +1,17 @@
<%- include('top') %>
<script>
//call socket.io
$(document).ready(async function () {
app.api.get('latest-sensor-data/data', function (error, data) {
//console.log(data[0]);
$.scope.LatestSensorData.push(data[0]);
});
});
//call socket.io to get live data
app.socket.on("sensorData:new", function (data) {
console.log("new data!!")
console.log(data);
console.log(data[0]);
$.scope.LatestSensorData.update(data[0]);
});
</script>
@ -53,7 +61,7 @@
</header>
<!-- Page Content -->
<div class="container">
<div class="services-bar">
<div class="services-bar" jq-repeat="LatestSensorData">
<h1 class="my-4">Services</h1>
<!-- Services Section -->
<div class="row">
@ -61,7 +69,7 @@
<div class="card">
<h4 class="card-header">Air Quality Index</h4>
<div class="card-body text-center">
<p class="card-text display-4">15 - 18 PSI</p>
<p class="card-text display-4">{{ measurement.psi }} PSI</p>
</div>
<div class="card-footer">
<a href="/learnmore" class="btn btn-primary">Learn More</a>
@ -72,7 +80,7 @@
<div class="card">
<h4 class="card-header">Humidity</h4>
<div class="card-body text-center">
<p class="card-text display-4">70% - 75%</p>
<p class="card-text display-4">{{ measurement.humidity }} %</p>
</div>
<div class="card-footer">
<a href="/learnmore" class="btn btn-primary">Learn More</a>
@ -83,7 +91,7 @@
<div class="card">
<h4 class="card-header">Temperature</h4>
<div class="card-body text-center">
<p class="card-text display-4">30&deg; - 37&deg;</p>
<p class="card-text display-4">{{ measurement.temperature }}&deg;</p>
</div>
<div class="card-footer">
<a href="/learnmore" class="btn btn-primary">Learn More</a>
@ -92,9 +100,9 @@
</div>
<div class="col-lg-3 mb-4">
<div class="card">
<h4 class="card-header">Another Category</h4>
<h4 class="card-header">Wind Speed</h4>
<div class="card-body text-center">
<p class="card-text display-4">values</p>
<p class="card-text display-4">{{ measurement.windspeed }} Km/h </p>
</div>
<div class="card-footer">
<a href="/learnmore" class="btn btn-primary">Learn More</a>

View File

@ -8,10 +8,9 @@
<ul id="sensorDataList">
<li jq-repeat='sensorData'>
rowid: {{ id }}
sensorId: {{ sensorid }}
created: {{ createdAt }}
location: {{ locationid }}
created: {{ createdAt }}
<br />
co: {{ measurement.co }}
humidity: {{ measurement.humidity }}
@ -30,7 +29,7 @@
<script type="text/javascript">
$(document).ready(async function () {
app.api.get('sensor-data/data?order=DESC&limit=40', function(error, data){
app.api.get('sensor-data/data?order=DESC&limit=6', function(error, data){
$.scope.sensorData.push(...data);
})
})

View File

@ -57,9 +57,7 @@
//check if user is logged in
app.auth.isLoggedIn(function (error, data) {
if (!error) {
console.log(error);
$.scope.getUsername.update(data);
if (location.pathname == "/profile") {
$.scope.getUserDetails.update(data);
}