Merge branch 'Dev-branch'

This commit is contained in:
newtbot 2024-01-21 03:59:15 +08:00
commit efcaaf87f6
27 changed files with 1229 additions and 442 deletions

2
api.MD
View File

@ -174,4 +174,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/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/api/v0/apikey/new -H "Content-Type: application/json" -X POST -d '{"userid": "2", "permission": "canRead"}' curl localhost/api/v0/apikey/new -H "Content-Type: application/json" -X POST -d '{"userid": "5", "permission": "canRead"}'

View File

@ -61,6 +61,7 @@ const apikeyModel = sequelize.define(
timestamps: true, timestamps: true,
} }
); );
apikeyModel.belongsTo(userModel);
module.exports = { apikeyModel }; module.exports = { apikeyModel };

View File

@ -19,6 +19,26 @@ const userModel = sequelize.define(
isNumeric: true, isNumeric: true,
}, },
}, },
firstname: {
type: DataTypes.STRING,
allowNull: false,
length: 60,
validate: {
notEmpty: true,
len: [1, 60],
isAlpha: true, // will only allow letters
},
},
lastname: {
type: DataTypes.STRING,
allowNull: false,
length: 60,
validate: {
notEmpty: true,
len: [1, 60],
isAlpha: true, // will only allow letters
},
},
username: { username: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: false, allowNull: false,

View File

@ -3,45 +3,58 @@ const { apikeyModel } = require("../database/model/apikeyModel.js");
const { userModel } = require("../database/model/userModel.js"); const { userModel } = require("../database/model/userModel.js");
const { Op, Sequelize } = require("sequelize"); const { Op, Sequelize } = require("sequelize");
const { generateUUID } = require("../functions/generateUUID.js"); const { generateUUID } = require("../functions/generateUUID.js");
const { hashPassword , comparePassword , hashAPIKey } = require("../functions/bcrypt.js"); const {
hashPassword,
comparePassword,
hashAPIKey,
} = require("../functions/bcrypt.js");
//helper function //getuser
//api/v0/user/me
async function getUserID(userid) {
//console.log(userid);
//console.log(userid.id);
let userRes = await userModel.findByPk(userid.id, {
attributes: {
exclude: ["password"],
},
});
if (!userRes) return false;
return userRes;
}
//api/v0/user/register
//api/v0/auth/register
/* Registering new user /* Registering new user
1) req.body is taken from html form or wtv 1) req.body is taken from html form or wtv
2) bcrpyt and hash the password on the server side 2) bcrpyt and hash the password on the server side
3) pass to db 3) pass to db
*/ */
async function addUser(user) { async function addUser(user) {
console.log(user);
//hash password //hash password
let hash = await hashPassword(user.password); let hash = await hashPassword(user.password);
const addRes = await userModel.create({ const addRes = await userModel.create({
firstname: user.firstname,
lastname: user.lastname,
username: user.username, username: user.username,
password: hash, password: hash,
email: user.email, email: user.email,
address: user.address, address: user.address,
phone: user.phone, phone: user.phone,
}); });
if (addRes){ if (addRes) {
return true; return true;
} } else {
else{
return false; return false;
} }
} }
//add token to db //api/v0/auth/login
async function addToken(userid , token) {
console.log(userid);
console.log(token);
}
async function loginUser(user) { async function loginUser(user) {
//look up username or email in db //look up username or email in db
const userRes = await userModel.findOne({ const userRes = await userModel.findOne({
@ -55,44 +68,19 @@ async function loginUser(user) {
}, },
], ],
}, },
}) });
//if user exists // Make sure user exists
if (userRes){ if (!userRes) return false;
//compare password
// Compare passwords
let match = await comparePassword(user.password, userRes.password); let match = await comparePassword(user.password, userRes.password);
if (match){ if (!match) return false;
console.log(userRes.id); //console.log('loginUser', userRes.id, userRes.username);
console.log(userRes.username);
//generate token //generate token
let token = await generateUUID(); let token = await addAPIKey(userRes.id, "auto-generated");
//add to db
addToken(userRes.id, token);
//sucessful login
/*
1) generate token
2) store in db and localstorage (maybe hash it?)
3) return userid and username and token and store in localstorage
*/
return { token: token, userid: userRes.id, username: userRes.username }; return { token: token, userid: userRes.id, username: userRes.username };
}
else {
return false;
}
}
else{
return false;
}
}
async function getAPIKey() {
const apikey = await apikeyModel.findAll();
return apikey;
} }
/* /*
@ -103,27 +91,47 @@ async function getAPIKey() {
5) you give the user rowid-uuidv4 5) you give the user rowid-uuidv4
6) store in database 6) store in database
*/ */
//can be used for api key or token. Both are the same logic
async function addAPIKey(userId, permission) { async function addAPIKey(userId, permission) {
let token = await generateUUID(); let hashtoken = await generateUUID();
let usertoken = userId + "-" + token; let apikey = await hashAPIKey(hashtoken);
let apikey = await hashAPIKey(token);
console.log(token); let token = await apikeyModel.create({
console.log(apikey);
await apikeyModel.create({
userid: userId, userid: userId,
apikey: apikey, apikey: apikey,
permission: permission permission: permission,
}); });
//user token with - tokenid is table id
//user token with - return token.id + "-" + hashtoken;
return usertoken;
} }
//api/v0/user/logout
async function deleteUserToken(token) {
//get row id
let splitAuthToken = token.split("-");
let rowid = splitAuthToken[0];
//console.log(rowid);
//delete from db
let delRes = await apikeyModel.destroy({
where: {
id: rowid,
},
});
if (!delRes) return false;
return true;
}
module.exports = { module.exports = {
getUserID,
addUser, addUser,
loginUser, loginUser,
addAPIKey, addAPIKey,
deleteUserToken,
}; };

View File

@ -21,6 +21,8 @@ bcrypt.hash(myPlaintextPassword, saltRounds, function(err, hash) {
}); });
*/ */
//hash for pass or token lol doesnt matter
async function hashPassword(password) { async function hashPassword(password) {
return await bcrypt.hash(password, saltRounds); return await bcrypt.hash(password, saltRounds);
} }
@ -29,6 +31,7 @@ async function hashAPIKey(apikey) {
return await bcrypt.hash(apikey, saltRounds); return await bcrypt.hash(apikey, saltRounds);
} }
//can be used to compare password or token
async function comparePassword(password, hash) { async function comparePassword(password, hash) {
return await bcrypt.compare(password, hash); return await bcrypt.compare(password, hash);
} }

View File

@ -1,4 +1,30 @@
/*v const { apikeyModel } = require("../database/model/apiKeyModel");
1) check if token proided by JSON req is valid against db const { userModel } = require("../database/model/userModel");
2) if valid its passed to next() const { comparePassword } = require("../functions/bcrypt");
*/
async function auth(req, res, next){
try{
// let user = await Auth.checkToken({token: req.header('auth-token')});
let authToken = req.header('auth-token');
let splitAuthToken = authToken.split('-');
let rowid = splitAuthToken[0];
let suppliedToken = splitAuthToken.slice(1).join('-');
//get from db
let token = await apikeyModel.findByPk(rowid, {include: userModel});
//compare
let isMatch = await comparePassword(suppliedToken, token.apikey);
if (!isMatch) return false;
//else do logic
//pass hashed token to req.token (IMPORTANT ITS NOT PASSED TO CLIENT)
req.token = token
req.user = await token.getUser();
next();
}catch(error){
next(error);
}
}
module.exports = { auth };

View File

@ -13,17 +13,17 @@ app.set("views", path.join(__dirname, "../views"));
app.set("view engine", "ejs"); app.set("view engine", "ejs");
// Have express server static content( images, CSS, browser JS) from the public // Have express server static content( images, CSS, browser JS) from the public
// local folder.
app.use(express.static(path.join(__dirname, "../public"))); app.use(express.static(path.join(__dirname, "../public")));
//middleware logic ( called by next() ) //middleware logic ( called by next() )
//add token middeware upon login to validate routes that require token const auth = require("../middleware/authChecker");
//route logic //route logic
app.use("/api/v0", require("../routes/api_routes")); //consumerWebsite\routes\api_routes.js app.use("/api/v0", require("../routes/api_routes"));
//render logic //render logic
app.use("/", require("../routes/render")); //consumerWebsite\routes\render.js app.use("/", require("../routes/render"));
// Catch 404 and forward to error handler. If none of the above routes are // Catch 404 and forward to error handler. If none of the above routes are
// used, this is what will be called. // used, this is what will be called.

View File

@ -3801,3 +3801,15 @@
.fas { .fas {
font-family: 'Font Awesome 5 Free'; font-family: 'Font Awesome 5 Free';
font-weight: 900; } font-weight: 900; }
.contact-right p {
/* Your CSS styles here */
color: #4e3914;
font-size: 16px;
/* Add any other styles you need */
}
.card-text {
color: #000000;
}

View File

@ -0,0 +1,526 @@
@charset "utf-8";
/* RESET
----------------------------------------------------------------------------------------*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size:100%;
font: inherit;
vertical-align: baseline;
}
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
display: block;
}
img, embed, object, video { max-width: 100%; }
.ie6 img.full, .ie6 object.full, .ie6 embed, .ie6 video { width: 100%; }
/* BASE
----------------------------------------------------------------------------------------*/
*{
-webkit-transition: all 0.3s ease;
-moz-transition: all 0.3s ease;
-o-transition: all 0.3s ease;
-ms-transition: all 0.3s ease;
transition: all 0.3s ease;
}
html,
body{
position:relative;
min-height: 100%;
height: 100%;
-webkit-backface-visibility: hidden;
font-family: 'Roboto', sans-serif;
}
strong{
font-weight: 500;
}
i{
font-style: italic;
}
.overflow-hidden{
position: relative;
overflow: hidden;
}
.content a{
color: #00a8e3;
text-decoration: none;
}
.content a:hover{
text-decoration: underline;
}
.scroll-to-link{
cursor: pointer;
}
p, .content ul, .content ol{
font-size: 14px;
color: #ffffff;
margin-bottom: 16px;
line-height: 1.6;
font-weight: 300;
}
.content h1:first-child{
font-size: 1.333em;
color: #034c8f;
padding-top: 2.5em;
text-transform: uppercase;
border-top: 1px solid rgba(255,255,255,0.3);
border-top-width: 0;
margin-top: 0;
margin-bottom: 1.3em;
clear: both;
}
code,
pre{
font-family: 'Source Code Pro', monospace;
}
.higlighted{
background-color: rgba(0,0,0,0.05);
padding: 3px;
border-radius: 3px;
}
/* LEFT-MENU
----------------------------------------------------------------------------------------*/
.left-menu{
position: fixed;
z-index: 3;
top: 0;
left: 0;
bottom: 0;
width: 300px;
box-sizing: border-box;
background-color: #f4f5f8;
overflow-x: hidden;
font-size: 18px;
}
.left-menu .content-infos {
position: relative;
padding: 12px 13.25%;
margin-bottom: 20px;
}
.left-menu .info {
position: relative;
font-size: 14px;
margin-top: 5px;
color: #777A7A;
}
.left-menu .info b {
font-weight: 500;
color: #034c8f;
}
.content-logo{
position: relative;
display: block;
width: 100%;
box-sizing: border-box;
padding: 1.425em 11.5%;
padding-right: 0;
}
.content-logo img{
display: inline-block;
max-width: 70%;
vertical-align: middle;
}
.content-logo span{
display: inline-block;
margin-left: 10px;
vertical-align: middle;
color: #323F4C;
font-size: 1.1em;
}
.content-menu{
margin: 2em auto 2em;
padding: 0 0 100px;
}
.content-menu ul{
list-style: none;
margin: 0;
padding: 0;
line-height: 28px;
}
.content-menu ul li{
list-style: none;
margin: 0;
padding: 0;
line-height: 0;
}
.content-menu ul li:hover,
.content-menu ul li.active{
background-color:#DCDEE9;
}
.content-menu ul li:hover a,
.content-menu ul li.active a{
color: #00a8e3;
}
@media (hover: none) {
.content-menu ul li:not(.active):hover {
background-color: inherit;
}
.content-menu ul li:not(.active):hover a {
color: #777A7A;
}
}
.content-menu ul li a{
padding: 12px 13.25%;
color: #777A7A;
letter-spacing: 0.025em;
line-height: 1.1;
display: block;
text-transform: capitalize;
}
/* CONTENT-PAGE
----------------------------------------------------------------------------------------*/
.content-page {
position: relative;
box-sizing: border-box;
margin-left: 300px;
z-index: 2;
background-color: #fff;
min-height: 100%;
padding-bottom: 1px;
}
.content-code{
width: 50%;
position: absolute;
right: 0;
top: 0;
bottom: 0;
background-color: #323f4c;
border-color: #323f4c;
}
.content {
position: relative;
z-index: 30;
}
.content h1,
.content h2,
.content h3,
.content h4,
.content h5,
.content h6,
.content p,
.content table,
.content aside,
.content dl,
.content ul,
.content ol,
.content .central-overflow-x {
margin-right: 50%;
padding: 0 28px;
box-sizing: border-box;
display: block;
max-width: 680px;
}
.content .central-overflow-x {
margin-right: calc(50% + 28px);
margin-left: 28px;
padding: 0;
overflow-y: hidden;
max-width: 100%;
display: block;
}
.content p .central-overflow-x {
margin-right: 0;
margin-left: 0;
}
.break-word {
word-break: break-word;
overflow-wrap: break-word;
word-wrap: break-word;
}
.content ul,
.content ol {
padding: 0 44px;
}
.content h2,
.content h3,
.content h4,
.content h5,
.content h6 {
font-size: 15px;
margin-top: 2.5em;
margin-bottom: 0.8em;
color: #034c8f;
text-transform: uppercase;
}
.content h2{
font-size: 1.333em;
}
.content h4{
color: #00a8e3;
margin-top: 0;
text-transform: none;
font-size: 14px;
margin-bottom: 0.2em;
}
.content-page .content p,
.content-page .content pre {
max-width: 680px;
}
.content pre,
.content blockquote {
background-color: #323f4c;
border-color: #323f4c;
color: #fff;
padding: 0 28px 2em;
margin: 0;
width: 50%;
float: right;
clear: right;
box-sizing: border-box;
}
.content pre code, .content pre {
font-size: 12px;
line-height: 1.5;
}
.content blockquote,
.content pre,
.content pre code{
padding-top: 0;
margin-top: 0;
}
.content pre code{
margin-top: -2em;
}
.content table {
font-size: 0.825em;
margin-bottom: 1.5em;
border-collapse: collapse;
border-spacing: 0;
}
.content table tr:last-child {
border-bottom: 1px solid #ccc;
}
.content table th {
font-size: 0.925em;
padding: 5px 18px 5px 0;
border-bottom: 1px solid #ccc;
vertical-align: bottom;
text-align: left;
line-height: 1.6;
}
.content table td {
padding: 5px 18px 5px 0;
text-align: left;
vertical-align: top;
line-height: 1.6;
font-family: 'Roboto', sans-serif;
font-weight: 300;
color: #777A7A;
}
/* burger-menu-icon
----------------------------------------------------------------------------------------*/
.burger-menu-icon {
background-color: transparent;
border: none;
cursor: pointer;
display: inline-block;
vertical-align: middle;
padding: 0;
position: absolute;
right: 26px;
top: 26px;
display: none;
}
.burger-menu-icon .line {
fill: none;
stroke: #000;
stroke-width: 6;
transition: stroke-dasharray 600ms cubic-bezier(0.4, 0, 0.2, 1),
stroke-dashoffset 600ms cubic-bezier(0.4, 0, 0.2, 1);
}
.burger-menu-icon .line1 {
stroke-dasharray: 60 207;
stroke-width: 6;
}
.burger-menu-icon .line2 {
stroke-dasharray: 60 60;
stroke-width: 6;
}
.burger-menu-icon .line3 {
stroke-dasharray: 60 207;
stroke-width: 6;
}
html.menu-opened .burger-menu-icon .line1 {
stroke-dasharray: 90 207;
stroke-dashoffset: -134;
stroke-width: 6;
}
html.menu-opened .burger-menu-icon .line2 {
stroke-dasharray: 1 60;
stroke-dashoffset: -30;
stroke-width: 6;
}
html.menu-opened .burger-menu-icon .line3 {
stroke-dasharray: 90 207;
stroke-dashoffset: -134;
stroke-width: 6;
}
/* ONE CONTENT COLUMN VERSION
----------------------------------------------------------------------------------------*/
body.one-content-column-version .content h1,
body.one-content-column-version .content h2,
body.one-content-column-version .content h3,
body.one-content-column-version .content h4,
body.one-content-column-version .content h5,
body.one-content-column-version .content h6,
body.one-content-column-version .content p,
body.one-content-column-version .content table,
body.one-content-column-version .content ul,
body.one-content-column-version .content ol,
body.one-content-column-version .content aside,
body.one-content-column-version .content dl,
body.one-content-column-version .content ul,
body.one-content-column-version .content ol {
margin-right: 0;
max-width: 100%;
}
body.one-content-column-version .content-page .content p,
body.one-content-column-version .content-page .content pre {
max-width: 100%;
}
body.one-content-column-version .content-page {
background-color: #323f4c;
}
body.one-content-column-version .content h1:first-child,
body.one-content-column-version .content h2,
body.one-content-column-version .content h3,
body.one-content-column-version .content h4,
body.one-content-column-version .content h5,
body.one-content-column-version .content h6 {
color: #59C3C3;
}
body.one-content-column-version p {
color: #D6F0F0;
}
body.one-content-column-version .content table td {
color: #D6F0F0;
}
body.one-content-column-version .content thead {
color: #417179;
}
/* RESPONSIVE
----------------------------------------------------------------------------------------*/
@media only screen and (max-width:980px){
.content h1, .content h2, .content h3, .content h4, .content h5, .content h6, .content p, .content table, .content ul, .content ol, .content aside, .content dl, .content ul, .content ol {
margin-right: 0;
}
.content .central-overflow-x {
margin: 0;
padding: 0 28px;
}
.content-code{
display: none;
}
.content pre, .content blockquote {
margin: 20px 0;
padding: 28px;
display: block;
width: auto;
float: none;
}
.content pre code {
margin-top: 0;
}
}
@media only screen and (max-width:680px){
html {
scroll-padding-top: 83px;
}
html.menu-opened {
overflow: hidden;
}
.left-menu {
position: relative;
width: auto;
}
.left-menu .content-menu {
position: fixed;
width: 400px;
max-width: 90vw;
z-index: 3;
top: 0;
bottom: 0;
right: -405px;
left: auto;
background-color: #fff;
margin: 0;
overflow-x: hidden;
padding-top: 83px;
padding-bottom: 20px;
}
.left-menu .content-menu ul {
position: relative;
}
.left-menu .mobile-menu-closer {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 2;
background-color: rgba(50, 63, 76, .5);
opacity: 0;
visibility: hidden;
}
html.menu-opened .left-menu .mobile-menu-closer {
opacity: 1;
visibility: visible;
}
html.menu-opened .left-menu .content-menu {
right: 0;
}
.left-menu .content-logo {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 4;
background-color: #f4f5f8;
}
.content-logo .logo {
margin-right: 65px;
}
.content-page{
margin-left: 0;
padding-top: 83px;
}
.burger-menu-icon {
display: block;
}
}
/* BROWSER AND NON-SEMANTIC STYLING
----------------------------------------------------------------------------------------*/
.cf:before, .cf:after { content: ""; display: block; }
.cf:after { clear: both; }
.ie6 .cf { zoom: 1 }

View File

@ -73,6 +73,21 @@ button.btn-secondary:hover{
color: #ffffff; color: #ffffff;
border-radius: 4.8px; border-radius: 4.8px;
} }
.btn-outline-danger{
width: 78px;
height: 40px;
padding-top: 8px;
font-size: 16px;
}
.btn-outline-info{
width: 78px ;
height: 40px ;
padding-top: 8px;
font-size: 16px;
}
.navbar-expand-lg.top-nav .navbar-nav .dropdown-menu{ .navbar-expand-lg.top-nav .navbar-nav .dropdown-menu{
margin: 0px; margin: 0px;
box-shadow: 3px 5px 15px rgba(0,0,0, .15); box-shadow: 3px 5px 15px rgba(0,0,0, .15);

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -0,0 +1,88 @@
var elements = [];
[].forEach.call(document.querySelectorAll('.scroll-to-link'), function (div) {
div.onclick = function (e) {
e.preventDefault();
var target = this.dataset.target;
document.getElementById(target).scrollIntoView({ behavior: 'smooth' });
var elems = document.querySelectorAll(".content-menu ul li");
[].forEach.call(elems, function (el) {
el.classList.remove("active");
});
this.classList.add("active");
return false;
};
});
document.getElementById('button-menu-mobile').onclick = function (e) {
e.preventDefault();
document.querySelector('html').classList.toggle('menu-opened');
}
document.querySelector('.left-menu .mobile-menu-closer').onclick = function (e) {
e.preventDefault();
document.querySelector('html').classList.remove('menu-opened');
}
function debounce (func) {
var timer;
return function (event) {
if (timer) clearTimeout(timer);
timer = setTimeout(func, 100, event);
};
}
function calculElements () {
var totalHeight = 0;
elements = [];
[].forEach.call(document.querySelectorAll('.content-section'), function (div) {
var section = {};
section.id = div.id;
totalHeight += div.offsetHeight;
section.maxHeight = totalHeight - 25;
elements.push(section);
});
onScroll();
}
function onScroll () {
var scroll = window.pageYOffset;
console.log('scroll', scroll, elements)
for (var i = 0; i < elements.length; i++) {
var section = elements[i];
if (scroll <= section.maxHeight) {
var elems = document.querySelectorAll(".content-menu ul li");
[].forEach.call(elems, function (el) {
el.classList.remove("active");
});
var activeElems = document.querySelectorAll(".content-menu ul li[data-target='" + section.id + "']");
[].forEach.call(activeElems, function (el) {
el.classList.add("active");
});
break;
}
}
if (window.innerHeight + scroll + 5 >= document.body.scrollHeight) { // end of scroll, last element
var elems = document.querySelectorAll(".content-menu ul li");
[].forEach.call(elems, function (el) {
el.classList.remove("active");
});
var activeElems = document.querySelectorAll(".content-menu ul li:last-child");
[].forEach.call(activeElems, function (el) {
el.classList.add("active");
});
}
}
calculElements();
window.onload = () => {
calculElements();
};
window.addEventListener("resize", debounce(function (e) {
e.preventDefault();
calculElements();
}));
window.addEventListener('scroll', function (e) {
e.preventDefault();
onScroll();
});

View File

@ -134,7 +134,6 @@ app.api = (function (app) {
complete: function (res, text) { complete: function (res, text) {
callback( callback(
text !== "success" ? res.statusText : null, text !== "success" ? res.statusText : null,
//console.log(res.responseText),
JSON.parse(res.responseText), JSON.parse(res.responseText),
res.status res.status
); );
@ -151,8 +150,9 @@ app.auth = (function (app) {
localStorage.setItem("APIToken", token); localStorage.setItem("APIToken", token);
} }
function setUserId(userId) { function setUserId(userid) {
localStorage.setItem("userId", userId); console.log("userid", userid);
localStorage.setItem("userid", userid);
} }
function setUsername(username) { function setUsername(username) {
@ -185,22 +185,36 @@ app.auth = (function (app) {
*/ */
function logOut(callback) { function logOut(callback) {
localStorage.removeItem("APIToken"); //call logout route
localStorage.removeItem("userId"); $.ajax({
localStorage.removeItem("username"); type: "DELETE",
url: "/api/v0/user/logout",
headers: {
"auth-token": app.auth.getToken(),
},
contentType: "application/json; charset=utf-8",
dataType: "json",
complete: function (res, text) {
callback(
text !== "success" ? res.statusText : null,
JSON.parse(res.responseText),
res.status
);
},
});
//remove token from db NOT the api key. localStorage.removeItem("APIToken");
localStorage.removeItem("userid");
localStorage.removeItem("username");
callback(); callback();
} }
function forceLogin() { function forceLogin() {
$.holdReady(true);
app.auth.isLoggedIn(function (error, isLoggedIn) { app.auth.isLoggedIn(function (error, isLoggedIn) {
if (error || !isLoggedIn) { if (error || !isLoggedIn) {
app.auth.logOut(function () {}); app.auth.logOut(function () {
location.replace(`/login`); location.replace(`/login`);
} else { });
$.holdReady(false);
} }
}); });
} }
@ -215,6 +229,18 @@ app.auth = (function (app) {
window.location.href = location.href.replace(location.replace(`/`)) || "/"; window.location.href = location.href.replace(location.replace(`/`)) || "/";
} }
//if isLoggedin is true, redirect user away from login / register page
function redirectIfLoggedIn() {
$.holdReady(true);
app.auth.isLoggedIn(function (error, isLoggedIn) {
if (error || isLoggedIn) {
location.replace(`/`);
} else {
$.holdReady(false);
}
});
}
return { return {
getToken: getToken, getToken: getToken,
setToken: setToken, setToken: setToken,
@ -226,6 +252,7 @@ app.auth = (function (app) {
forceLogin, forceLogin,
logInRedirect, logInRedirect,
homeRedirect, homeRedirect,
redirectIfLoggedIn,
}; };
})(app); })(app);

View File

@ -1,193 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>N & LW Lawn Care - Landscaping Bootstrap4 HTML5 Responsive Template </title>
<!-- Bootstrap core CSS -->
<link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<!-- Fontawesome CSS -->
<link href="css/all.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="css/style.css" rel="stylesheet">
</head>
<body>
<!-- Navigation -->
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-light top-nav fixed-top">
<div class="container">
<a class="navbar-brand" href="index.html">
<img src="images/logo.png" alt="logo" />
</a>
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse"
data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false"
aria-label="Toggle navigation">
<span class="fas fa-bars"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="index.html">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="news.html">News</a>
</li>
<li class="nav-item">
<a class="nav-link" href="contactform.html">Contact</a>
</li>
<li class="nav-item">
<a class="nav-link" href="profile.html">Profile</a>
</li>
<li class="nav-item">
<a class="nav-link" href="signuplogin.html">Logout</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="full-title">
<div class="container">
<h1 class="mt-4 mb-3">Profile
</h1>
</div>
</div>
<br>
<br>
<div class="centered-content">
<div class="container">
<div class="row">
<div class="col-md-3 border-right">
<div class="d-flex flex-column align-items-center text-center p-3 py-5"><img
class="rounded-circle mt-5" width="150px"
src="https://st3.depositphotos.com/15648834/17930/v/600/depositphotos_179308454-stock-illustration-unknown-person-silhouette-glasses-profile.jpg">
</div>
</div>
<div class="col-md-5 border-right">
<div class="p-3 py-5">
<div class="d-flex justify-content-between align-items-center mb-3">
<h4 class="text-right">Profile Settings</h4>
</div>
<div class="row mt-2">
<div class="col-md-6"><label class="labels">Name</label><input type="text"
class="form-control" placeholder="first name" value=""></div>
<div class="col-md-6"><label class="labels">Surname</label><input type="text"
class="form-control" value="" placeholder="surname"></div>
</div>
<div class="row mt-3">
<div class="col-md-12"><label class="labels">Mobile Number</label><input type="text"
class="form-control" placeholder="enter phone number" value=""></div>
<div class="col-md-12"><label class="labels">Address</label><input type="text"
class="form-control" placeholder="enter address" value=""></div>
<div class="col-md-12"><label class="labels">Email</label><input type="text"
class="form-control" placeholder="enter email" value=""></div>
<div class="col-md-12"><label class="labels">Password</label><input type="text"
class="form-control" placeholder="enter password" value=""></div>
<div class="col-md-12"><label class="labels">Password</label><input type="text"
class="form-control" placeholder="re enter password" value=""></div>
</div>
<div class="mt-2 text-center">
<button class="btn btn-sm btn-secondary change-password-button" type="button">Change
Password</button>
</div>
<div class="mt-5 text-center"><button class="btn btn-primary profile-button" type="button">Save
Profile</button></div>
</div>
</div>
</div>
</div>
</div>
<br>
<footer class="footer">
<div class="container bottom_border">
<div class="row">
<div class="col-lg-3 col-md-6 col-sm-6 col">
<h5 class="headin5_amrc col_white_amrc pt2">Find us</h5>
<p><i class="fa fa-location-arrow"></i> Blk 645 Jalan Tenaga</p>
<p><i class="fa fa-phone"></i> +65 90064959</p>
<p><i class="fa fa fa-envelope"></i> Leongdingxuan@gmail.com </p>
</div>
<div class="col-lg-3 col-md-6 col-sm-6 col">
<h5 class="headin5_amrc col_white_amrc pt2">Follow us</h5>
<!--headin5_amrc ends here-->
<ul class="footer_ul2_amrc">
<li>
<a href="#"><i class="fab fa-facebook-f fleft padding-right"></i> </a>
<a href="#">https://www.facebook.com/</a></p>
</li>
<li>
<a href="#"><i class="fab fa-instagram fleft padding-right"></i> </a>
<a href="#">https://www.instagram.com/</a></p>
</li>
<li>
<a href="#"><i class="fab fa-twitter fleft padding-right"></i> </a>
<a href="#">https://twitter.com/</a></p>
</li>
</ul>
<!--footer_ul2_amrc ends here-->
</div>
<div class="col-lg-3 col-md-6 col-sm-6">
<h5 class="headin5_amrc col_white_amrc pt2">Quick links</h5>
<!--headin5_amrc-->
<ul class="footer_ul_amrc">
<li><a href="#">Home</a></li>
<li><a href="#">News</a></li>
<li><a href="#">Contact</a></li>
</ul>
<!--footer_ul_amrc ends here-->
</div>
<div class="col-lg-3 col-md-6 col-sm-6 ">
<h5 class="headin5_amrc col_white_amrc pt2">News</h5>
<!--headin5_amrc-->
<ul class="footer_ul_amrc">
<li class="media">
<div class="media-left">
<img class="img-fluid" src="images/post-img-01.jpg" alt="" />
</div>
<div class="media-body">
<p>Singapore's air quality ...</p>
<span>7 oct 2023</span>
</div>
</ul>
<ul class="footer_ul_amrc">
<li class="media">
<div class="media-left">
<img class="img-fluid" src="images/post-img-01.jpg" alt="" />
</div>
<div class="media-body">
<p>Singapore Government ...</p>
<span>29 Sep 2023</span>
</div>
</ul>
<ul class="footer_ul_amrc">
<li class="media">
<div class="media-left">
<img class="img-fluid" src="images/post-img-01.jpg" alt="" />
</div>
<div class="media-body">
<p>High risk of severe ...</p>
<span>22 Jun 2023</span>
</div>
</ul>
</div>
</div>
</div>
<div class="container text-center">
<br>
<p>All Rights Reserved. &copy; 2023 <a href="#">EcoSaver</a>
</p>
</div>
</footer>
<!-- Bootstrap core JavaScript -->
<script src="vendor/jquery/jquery.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
</body>
</html>

View File

@ -1,10 +1,14 @@
'use strict'; 'use strict';
const router = require('express').Router(); const router = require('express').Router();
const { auth } = require("../middleware/authChecker")
router.use('/user', require('./user'));
router.use('/auth', require('./auth'));
router.use('/apikey', require('./apikey')); router.use('/apikey', require('./apikey'));
router.use('/user', auth ,require('./user'));
module.exports = router; module.exports = router;

View File

@ -0,0 +1,56 @@
const { addUser, loginUser } = require("../functions/apiDatabase.js");
const express = require("express");
const router = express.Router();
// /user/register
router.post("/register", async (req, res, next) => {
try {
console.log(req.body);
let Res = await addUser(req.body);
if (Res == false) {
let error = new Error("UserRegFailed");
error.message = "The user failed to be craated";
error.status = 400;
return next(error);
}
else{
return res.json({
message: "User created successfully",
});
}
} catch (error) {
console.error(error);
next(error);
}
});
//login
router.post("/login", async (req, res, next) => {
try {
let Res = await loginUser(req.body);
if (Res == false) {
let error = new Error("User Login Failed");
error.status = 400;
return next(error);
}
else{
//pass res back to form to be set in local storage
console.log("my res" , Res);
return res.json({
message: "User login successfully",
token: Res.token,
userid: Res.userid,
username: Res.username,
});
}
} catch (error) {
console.error(error);
next(error);
}
});
module.exports = router;

View File

@ -61,4 +61,14 @@ router.get('/contact', function(req, res, next) {
res.render('contact'); res.render('contact');
}); });
//api doc
router.get('/api', function(req, res, next) {
res.render('api');
});
//profile page
router.get('/profile', function(req, res, next) {
res.render('profile');
});
module.exports = router; module.exports = router;

View File

@ -1,100 +1,58 @@
const { addUser, loginUser } = require("../functions/apiDatabase.js"); const { getUserID , deleteUserToken } = require("../functions/apiDatabase.js");
const express = require("express"); const express = require("express");
const router = express.Router(); const router = express.Router();
// /user/register //api/v0/user/me
router.post("/register", async (req, res, next) => { //getbyid
router.get("/me", async function (req, res, next) {
try { try {
let Res = await addUser(req.body);
if (Res == false) { //console.log(req.user);
let error = new Error("UserRegFailed"); let user = await getUserID(req.user);
error.message = "The user failed to be craated"; if (!user) {
let error = new Error("User not found");
error.status = 400; error.status = 400;
return next(error); return next(error);
} }
else{ res.json({
return res.json({ user: user,
message: "User created successfully",
}); });
}
} catch (error) { } catch (error) {
console.error(error);
next(error); next(error);
} }
}); });
//login //logout
router.post("/login", async (req, res, next) => { router.delete('/logout', async function(req, res, next){
try { try{
let Res = await loginUser(req.body); /*
if (Res == false) { let authToken = req.header('auth-token');
let error = new Error("User Login Failed"); let userDel = await deleteUserToken(authToken);
if (!userDel) {
let error = new Error("User not found");
error.status = 400; error.status = 400;
return next(error); return next(error);
} }
else{ */
//pass res back to form to be set in local storage //destroy method call on seq object
console.log(Res); req.token.destroy();
return res.json({ // DO NOT CALL THIS!!! IT WILL DESTROY USERMODEL SEQ OBJ
message: "User login successfully", //req.user.destroy();
token: Res.token, res.json({
userId: Res.userid, message: "User logged out successfully",
username: Res.username,
}); });
} }catch(error){
} catch (error) {
console.error(error);
next(error); next(error);
} }
}); });
//update //update
//delete //delete
//getbyid
module.exports = router;
/*
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"}'
'use strict';
const router = require('express').Router();
const {User} = require('../models/user');
router.get('/', async function(req, res, next){
try{
return res.json({
results: await User[req.query.detail ? "listDetail" : "list"]()
});
}catch(error){
next(error);
}
});
router.get('/me', async function(req, res, next){
try{
return res.json(await User.get({uid: req.user.uid}));
}catch(error){
next(error);
}
});
router.get('/:uid', async function(req, res, next){
try{
return res.json({
results: await User.get(req.params.uid),
});
}catch(error){
next(error);
}
});
module.exports = router; module.exports = router;
*/

View File

@ -0,0 +1,160 @@
<!--
API Documentation HTML Template - 1.0.1
Copyright © 2016 Florian Nicolas
Licensed under the MIT license.
https://github.com/ticlekiwi/API-Documentation-HTML-Template
!-->
<%- include('top') %>
<body class="one-content-column-version">
<div class="left-menu">
<div class="content-logo">
<div class="logo">
<img alt="platform by Emily van den Heever from the Noun Project" title="platform by Emily van den Heever from the Noun Project" src="images/apilogo.png" height="32" />
<span>API Documentation</span>
</div>
<button class="burger-menu-icon" id="button-menu-mobile">
<svg width="34" height="34" viewBox="0 0 100 100"><path class="line line1" d="M 20,29.000046 H 80.000231 C 80.000231,29.000046 94.498839,28.817352 94.532987,66.711331 94.543142,77.980673 90.966081,81.670246 85.259173,81.668997 79.552261,81.667751 75.000211,74.999942 75.000211,74.999942 L 25.000021,25.000058"></path><path class="line line2" d="M 20,50 H 80"></path><path class="line line3" d="M 20,70.999954 H 80.000231 C 80.000231,70.999954 94.498839,71.182648 94.532987,33.288669 94.543142,22.019327 90.966081,18.329754 85.259173,18.331003 79.552261,18.332249 75.000211,25.000058 75.000211,25.000058 L 25.000021,74.999942"></path></svg>
</button>
</div>
<div class="mobile-menu-closer"></div>
<div class="content-menu">
<div class="content-infos">
<div class="info"><b>Version:</b> 1.0.5</div>
<div class="info"><b>Last Updated:</b> 15th Sep, 2021</div>
</div>
<ul>
<li class="scroll-to-link active" data-target="content-get-started">
<a>GET STARTED</a>
</li>
<li class="scroll-to-link" data-target="content-get-characters">
<a>Get Characters</a>
</li>
<li class="scroll-to-link" data-target="content-errors">
<a>Errors</a>
</li>
</ul>
</div>
</div>
<div class="content-page">
<div class="content">
<div class="overflow-hidden content-section" id="content-get-started">
<h1>Get started</h1>
<p>
The Westeros API provides programmatic access to read Game of Thrones data. Retrieve a character, provide an oauth connexion, retrieve a familly, filter them, etc.
</p>
<p>
To use this API, you need an <strong>API key</strong>. Please contact us at <a href="mailto:jon.snow@nightswatch.wes">jon.snow@nightswatch.wes</a> to get your own API key.
</p>
</div>
<div class="overflow-hidden content-section" id="content-get-characters">
<h2>get characters</h2>
<p>
To get characters you need to make a POST call to the following url :<br>
<code class="higlighted break-word">http://api.westeros.com/character/get</code>
</p>
<br>
<h4>QUERY PARAMETERS</h4>
<table>
<thead>
<tr>
<th>Field</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>secret_key</td>
<td>String</td>
<td>Your API key.</td>
</tr>
<tr>
<td>search</td>
<td>String</td>
<td>(optional) A search word to find character by name.</td>
</tr>
<tr>
<td>house</td>
<td>String</td>
<td>
(optional) a string array of houses:
</td>
</tr>
<tr>
<td>alive</td>
<td>Boolean</td>
<td>
(optional) a boolean to filter alived characters
</td>
</tr>
<tr>
<td>gender</td>
<td>String</td>
<td>
(optional) a string to filter character by gender:<br> m: male<br> f: female
</td>
</tr>
<tr>
<td>offset</td>
<td>Integer</td>
<td>(optional - default: 0) A cursor for use in pagination. Pagination starts offset the specified offset.</td>
</tr>
<tr>
<td>limit</td>
<td>Integer</td>
<td>(optional - default: 10) A limit on the number of objects to be returned, between 1 and 100.</td>
</tr>
</tbody>
</table>
</div>
<div class="overflow-hidden content-section" id="content-errors">
<h2>Errors</h2>
<p>
The Westeros API uses the following error codes:
</p>
<table>
<thead>
<tr>
<th>Error Code</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td>X000</td>
<td>
Some parameters are missing. This error appears when you don't pass every mandatory parameters.
</td>
</tr>
<tr>
<td>X001</td>
<td>
Unknown or unvalid <code class="higlighted">secret_key</code>. This error appears if you use an unknow API key or if your API key expired.
</td>
</tr>
<tr>
<td>X002</td>
<td>
Unvalid <code class="higlighted">secret_key</code> for this domain. This error appears if you use an API key non specified for your domain. Developper or Universal API keys doesn't have domain checker.
</td>
</tr>
<tr>
<td>X003</td>
<td>
Unknown or unvalid user <code class="higlighted">token</code>. This error appears if you use an unknow user <code class="higlighted">token</code> or if the user <code class="higlighted">token</code> expired.
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>

View File

@ -85,4 +85,5 @@
<!-- Bootstrap core JavaScript --> <!-- Bootstrap core JavaScript -->
<script src="vendor/jquery/jquery.min.js"></script> <script src="vendor/jquery/jquery.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script> <script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<script src="js/api.js"></script>
</body> </body>

View File

@ -1,6 +1,7 @@
<%- include('top') %> <%- include('top') %>
<header class="slider-main"> <header class="slider-main">
<div id="carouselExampleIndicators" class="carousel slide carousel-fade" data-ride="carousel"> <div id="carouselExampleIndicators" class="carousel slide carousel-fade" data-ride="carousel">
<ol class="carousel-indicators"> <ol class="carousel-indicators">

View File

@ -14,7 +14,7 @@
<!-- Custom styles for this template --> <!-- Custom styles for this template -->
<link rel="stylesheet" href="css/sp.css" /> <link rel="stylesheet" href="css/sp.css" />
<link rel="stylesheet" href="css/contact.css" />
<!-- jQuery library --> <!-- jQuery library -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js" <script src="https://code.jquery.com/jquery-3.7.1.min.js"
@ -36,18 +36,23 @@
<!-- wait for DOC to be ready --> <!-- wait for DOC to be ready -->
<script> <script>
//make document ready
$(document).ready(function () { $(document).ready(function () {
//check if user is logged in
app.auth.isLoggedIn(function (error, data) { app.auth.isLoggedIn(function (error, data) {
if (data) { if (data) {
$('#cl-logout-button').show(); $('#cl-logout-button').show('fast');
$('#cl-profile-button').show(); $('#cl-profile-button').show('fast');
$('#cl-login-button').hide(); $('#cl-login-button').hide('fast');
} else { } else {
$('#cl-login-button').show(); $('#cl-login-button').show('fast');
} }
$('body').show('fast')
}); });
}); });
</script>
</script>
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-light top-nav fixed-top"> <nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-light top-nav fixed-top">
@ -70,6 +75,9 @@
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/contact">Contact</a> <a class="nav-link" href="/contact">Contact</a>
</li> </li>
<li class="nav-item">
<a class="nav-link" href="/api">API Doc</a>
</li>
<!-- profile button --> <!-- profile button -->
<div class="form-inline mt-2 mt-md-0"> <div class="form-inline mt-2 mt-md-0">
<a id="cl-profile-button" class="btn btn-outline-danger my-2 my-sm-0" href="/profile" <a id="cl-profile-button" class="btn btn-outline-danger my-2 my-sm-0" href="/profile"
@ -85,7 +93,7 @@
<button id="cl-logout-button" class="btn btn-outline-danger my-2 my-sm-0" <button id="cl-logout-button" class="btn btn-outline-danger my-2 my-sm-0"
onclick="app.auth.logOut(e => window.location.href='/')" style="display: none;"> onclick="app.auth.logOut(e => window.location.href='/')" style="display: none;">
<i class="fas fa-sign-out"></i> <i class="fas fa-sign-out"></i>
Log Out Logout
</button> </button>
</div> </div>
</ul> </ul>

View File

@ -0,0 +1,64 @@
<%- include('top') %>
<script type="text/javascript">
// Require login to see this page.
app.auth.forceLogin()
</script>
<div class="full-title">
<div class="container">
<h1 class="mt-4 mb-3">Profile
</h1>
</div>
</div>
<br>
<br>
<div class="centered-content">
<div class="container">
<div class="row">
<div class="col-md-3 border-right">
<div class="d-flex flex-column align-items-center text-center p-3 py-5"><img
class="rounded-circle mt-5" width="150px"
src="https://st3.depositphotos.com/15648834/17930/v/600/depositphotos_179308454-stock-illustration-unknown-person-silhouette-glasses-profile.jpg">
</div>
</div>
<div class="col-md-5 border-right">
<div class="p-3 py-5">
<div class="d-flex justify-content-between align-items-center mb-3">
<h4 class="text-right">Profile Settings</h4>
</div>
<div class="row mt-2">
<div class="col-md-6"><label class="labels">Name</label><input type="text"
class="form-control" placeholder="first name" value=""></div>
<div class="col-md-6"><label class="labels">Surname</label><input type="text"
class="form-control" value="" placeholder="surname"></div>
</div>
<div class="row mt-3">
<div class="col-md-12"><label class="labels">Mobile Number</label><input type="text"
class="form-control" placeholder="enter phone number" value=""></div>
<div class="col-md-12"><label class="labels">Address</label><input type="text"
class="form-control" placeholder="enter address" value=""></div>
<div class="col-md-12"><label class="labels">Email</label><input type="text"
class="form-control" placeholder="enter email" value=""></div>
<div class="col-md-12"><label class="labels">Password</label><input type="text"
class="form-control" placeholder="enter password" value=""></div>
<div class="col-md-12"><label class="labels">Password</label><input type="text"
class="form-control" placeholder="re enter password" value=""></div>
</div>
<div class="mt-2 text-center">
<button class="btn btn-sm btn-secondary change-password-button" type="button">Change
Password</button>
</div>
<div class="mt-5 text-center"><button class="btn btn-primary profile-button" type="button">Save
Profile</button></div>
</div>
</div>
</div>
</div>
</div>
<br>
<%- include('bot') %>

View File

@ -1,4 +1,7 @@
<%- include('logintop') %> <%- include('logintop') %>
<script type="text/javascript">
app.auth.redirectIfLoggedIn();
</script>
<body> <body>
<section class="wrapper"> <section class="wrapper">
@ -7,7 +10,9 @@
<header>Signup</header> <header>Signup</header>
<!-- localhost/api/v0/user/register --> <!-- localhost/api/v0/user/register -->
<!-- evalAjax Fires when status 200 is returned --> <!-- evalAjax Fires when status 200 is returned -->
<form action="user/register" onsubmit="formAJAX(this)" evalAJAX="app.auth.logInRedirect();"> <form action="auth/register" onsubmit="formAJAX(this)" evalAJAX="app.auth.logInRedirect();">
<input type="text" name="firstname" placeholder="First Name" required />
<input type="text" name="lastname" placeholder="Last Name" required />
<input type="text" name="username" placeholder="Username" required /> <input type="text" name="username" placeholder="Username" required />
<input type="text" name="email" placeholder="Email" required /> <input type="text" name="email" placeholder="Email" required />
<input type="text" name="address" placeholder="Address" required /> <input type="text" name="address" placeholder="Address" required />
@ -22,10 +27,10 @@
<header>Login</header> <header>Login</header>
<div class="card-header shadow actionMessage" style="display:none"></div> <div class="card-header shadow actionMessage" style="display:none"></div>
<!-- evalAjax Fires when status 200 is returned --> <!-- evalAjax Fires when status 200 is returned -->
<form action="user/login" onsubmit="formAJAX(this)" <form action="auth/login" onsubmit="formAJAX(this)"
evalAJAX="app.auth.homeRedirect(); evalAJAX="app.auth.homeRedirect();
app.auth.setToken(data.token); app.auth.setToken(data.token);
app.auth.setUserId(data.userId); app.auth.setUserId(data.userid);
app.auth.setUsername(data.username); app.auth.setUsername(data.username);
"> ">

View File

@ -1,11 +1,13 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content=""> <meta name="description" content="">
<meta name="author" content=""> <meta name="author" content="">
<meta http-equiv="cleartype" content="on">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap core CSS --> <!-- Bootstrap core CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"
@ -19,6 +21,12 @@
<link href="css/contact.css" rel="stylesheet"> <link href="css/contact.css" rel="stylesheet">
<link href="css/contact.css" rel="stylesheet">
<link rel="stylesheet" href="css/api.css" media="all">
<!-- weird api page cdn -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,300;0,400;0,500;1,300&family=Source+Code+Pro:wght@300&display=swap" rel="stylesheet">
<!-- jQuery library --> <!-- jQuery library -->
@ -28,32 +36,40 @@
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL"
crossorigin="anonymous"></script> crossorigin="anonymous"></script>
<!-- weird api page cdn -->
<!-- https://github.com/floriannicolas/API-Documentation-HTML-Template/tree/master -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.8.0/highlight.min.js"></script>
<!-- https://github.com/floriannicolas/API-Documentation-HTML-Template/tree/master -->
<script>
hljs.initHighlightingOnLoad();
</script>
<!-- jquery app.js --> <!-- jquery app.js -->
<script src="js/app.js"></script> <script src="js/app.js"></script>
</head> </head>
<body>
<!-- javascript function to check if user is auth --> <!-- javascript function to check if user is auth -->
<!-- wait for DOC to be ready -->
<script> <script>
//make document ready
$(document).ready(function () { $(document).ready(function () {
//check if user is logged in
app.auth.isLoggedIn(function (error, data) { app.auth.isLoggedIn(function (error, data) {
if (data) { if (data) {
$('#cl-logout-button').show(); $('#cl-logout-button').show('fast');
$('#cl-profile-button').show(); $('#cl-profile-button').show('fast');
$('#cl-login-button').hide(); $('#cl-login-button').hide('fast');
} else { } else {
$('#cl-login-button').show(); $('#cl-login-button').show('fast');
} }
$('body').show('fast')
}); });
}); });
</script>
</script>
<body>
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-light top-nav fixed-top"> <nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-light top-nav fixed-top">
<div class="container"> <div class="container">
<a class="navbar-brand" href="/"> <a class="navbar-brand" href="/">
@ -74,22 +90,24 @@
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/contact">Contact</a> <a class="nav-link" href="/contact">Contact</a>
</li> </li>
<li class="nav-item">
<a class="nav-link" href="/api">API Doc</a>
</li>
<!-- profile button --> <!-- profile button -->
<div class="form-inline mt-2 mt-md-0"> <div class="form-inline mt-2 mt-md-0">
<a id="cl-profile-button" class="btn btn-outline-danger my-2 my-sm-0" href="/profile" <!-- Profile Button -->
style="display: none;"> <a id="cl-profile-button" class="btn btn-outline-info btn-sm my-2 my-sm-0" href="/profile" style="display: none;">
<i class="fas fa-sign-out"></i> <i class="fas fa-sign-out"></i> Profile
Profile
</a> </a>
<a id="cl-login-button" class="btn btn-outline-danger my-2 my-sm-0"
onclick="app.auth.forceLogin()" style="display: none;"> <!-- Login Button -->
<i class="fas fa-sign-out"></i> <a id="cl-login-button" class="btn btn-outline-danger btn-sm my-2 my-sm-0" onclick="app.auth.forceLogin()" style="display: none;">
Login <i class="fas fa-sign-out"></i> Login
</a> </a>
<button id="cl-logout-button" class="btn btn-outline-danger my-2 my-sm-0"
onclick="app.auth.logOut(e => window.location.href='/')" style="display: none;"> <!-- Logout Button -->
<i class="fas fa-sign-out"></i> <button id="cl-logout-button" class="btn btn-outline-danger btn-sm my-2 my-sm-0" href="/" onclick="app.auth.logOut(e => window.location.href='/')" style="display: none;">
Log Out <i class="fas fa-sign-out"></i> Logut
</button> </button>
</div> </div>
</ul> </ul>
@ -99,35 +117,3 @@
</body> </body>
</html> </html>
<!--
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link active" href="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/news">News</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/contact">Contact</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/profile">Profile</a>
</li>
<li class="nav-item">
<div class="form-inline mt-2 mt-md-0">
<a id="cl-login-button" class="btn btn-outline-danger my-2 my-sm-0"
onclick="app.auth.forceLogin()" style="display: none;">
<i class="fas fa-sign-out"></i>
Login
</a>
<button id="cl-logout-button" class="btn btn-outline-danger my-2 my-sm-0"
onclick="app.auth.logOut(e => window.location.href='/')" style="display: none;">
<i class="fas fa-sign-out"></i>
Log Out
</button>
</div>
</li>
</ul>
-->

View File

@ -1,4 +1,5 @@
require('dotenv').config({ path: path.resolve(__dirname, '../../../.env') }) //import('dotenv').config({ path: path.resolve(__dirname, '../../../.env') })
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {

View File

@ -42,7 +42,7 @@ module.exports = { apikeyCheck };
//web server microservice //web server microservice
1) take user supplied rowid-apikey 1) take user supplied rowid-apikey
2) split the string by - 2) split the string by -
3) get the rowid 3) get the rowid or table id
4) get the apikey 4) get the apikey
5) compare the apikey with the one in database 5) compare the apikey with the one in database
6) if match, return true 6) if match, return true