Merge pull request #36 from Newtbot/Dev-branch

register blah
This commit is contained in:
noot 2024-01-19 16:05:52 +08:00 committed by GitHub
commit a4f178bb21
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 417 additions and 160 deletions

View File

@ -4,10 +4,6 @@ const app = express();
const port = 3000; const port = 3000;
const ejs = require("ejs"); const ejs = require("ejs");
const bodyParser = require("body-parser"); // Middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.json()); app.use(express.json());
app.set("json spaces", 2); app.set("json spaces", 2);

View File

@ -203,3 +203,51 @@ form
.form.login .back-to-login:hover { .form.login .back-to-login:hover {
text-decoration: underline; text-decoration: underline;
} }
.top-nav{
background-color: #ffffff !important;
}
.navbar-expand-lg.top-nav .navbar-nav .nav-link{
padding: 10px 15px;
color: #4e3914;
font-size: 14px;
font-weight: 300;
text-transform: uppercase;
}
.navbar-expand-lg.top-nav .navbar-nav .nav-link:hover{
background: #4eae3a;
color: #ffffff;
border-radius: 4.8px;
}
.navbar-expand-lg.top-nav .navbar-nav .nav-link.active{
background: #4eae3a;
color: #ffffff;
border-radius: 4.8px;
}
.navbar-expand-lg.top-nav .navbar-nav .dropdown-menu{
margin: 0px;
box-shadow: 3px 5px 15px rgba(0,0,0, .15);
border: none;
padding: 20px;
}
.navbar-expand-lg.top-nav .navbar-nav .dropdown-menu .dropdown-item{
font-size: 14px;
padding: 0px;
padding-bottom: 15px;
font-weight: 300;
}
.navbar-expand-lg.top-nav .navbar-nav .dropdown-menu .dropdown-item:last-child{
padding: 0px;
}
.navbar-expand-lg.top-nav .navbar-nav .dropdown-menu .dropdown-item:hover{
background: none;
color: #4eae3a;
}
.top-nav .navbar-toggler{
color: #4e3914;
border-color: #4e3914;
}
.top-nav .navbar-toggler:hover{
color: #4eae3a;
border-color: #4eae3a;
}

View File

@ -1,104 +1,165 @@
var app = {}; var app = {};
app.util = (function (app) {
function getUrlParameter(name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
var results = regex.exec(location.search);
return results === null
? ""
: decodeURIComponent(results[1].replace(/\+/g, " "));
}
function actionMessage(message, $target, type, callback) {
message = message || "";
$target = $target.closest("div.card").find(".actionMessage");
type = type || "info";
callback = callback || function () {};
if ($target.html() === message) return;
if ($target.html()) {
$target.slideUp("fast", function () {
$target.html("");
$target.removeClass(function (index, className) {
return (className.match(/(^|\s)bg-\S+/g) || []).join(" ");
});
if (message) return actionMessage(message, $target, type, callback);
$target.hide();
});
} else {
if (type) $target.addClass("bg-" + type);
message =
'<button class="action-close btn btn-sm btn-outline-dark float-right"><i class="fa-solid fa-xmark"></i></button>' +
message;
$target.html(message).slideDown("fast");
}
setTimeout(callback, 10);
}
$.fn.serializeObject = function () {
var arr = $(this).serializeArray(),
obj = {};
for (var i = 0; i < arr.length; i++) {
if (obj[arr[i].name] === undefined) {
obj[arr[i].name] = arr[i].value;
} else {
if (!(obj[arr[i].name] instanceof Array)) {
obj[arr[i].name] = [obj[arr[i].name]];
}
obj[arr[i].name].push(arr[i].value);
}
}
return obj;
};
return {
getUrlParameter: getUrlParameter,
actionMessage: actionMessage,
};
})(app);
app.api = (function (app) { app.api = (function (app) {
var baseURL = '/api/v0/' var baseURL = "/api/v0/";
function post(url, data, callback) { function post(url, data, callback) {
$.ajax({ $.ajax({
type: 'POST', type: "POST",
url: baseURL + url, url: baseURL + url,
headers: { headers: {
'auth-token': app.auth.getToken() //register will getr undefined token
//login will get valid token
"auth-token": app.auth.getToken(),
}, },
data: JSON.stringify(data), data: JSON.stringify(data),
contentType: "application/json; charset=utf-8", contentType: "application/json; charset=utf-8",
dataType: "json", dataType: "json",
complete: function (res, text) { complete: function (res, text) {
callback( callback(
text !== 'success' ? res.statusText : null, text !== "success" ? res.statusText : null,
JSON.parse(res.responseText), JSON.parse(res.responseText),
res.status res.status
) );
} },
}); });
} }
function put(url, data, callback) { function put(url, data, callback) {
$.ajax({ $.ajax({
type: 'PUT', type: "PUT",
url: baseURL + url, url: baseURL + url,
headers: { headers: {
'auth-token': app.auth.getToken() "auth-token": app.auth.getToken(),
}, },
data: JSON.stringify(data), data: JSON.stringify(data),
contentType: "application/json; charset=utf-8", contentType: "application/json; charset=utf-8",
dataType: "json", dataType: "json",
complete: function (res, text) { complete: function (res, text) {
callback( callback(
text !== 'success' ? res.statusText : null, text !== "success" ? res.statusText : null,
JSON.parse(res.responseText), JSON.parse(res.responseText),
res.status res.status
) );
} },
}); });
} }
function remove(url, callback, callback2) { function remove(url, callback, callback2) {
if (!$.isFunction(callback)) callback = callback2; if (!$.isFunction(callback)) callback = callback2;
$.ajax({ $.ajax({
type: 'delete', type: "delete",
url: baseURL + url, url: baseURL + url,
headers: { headers: {
'auth-token': app.auth.getToken() "auth-token": app.auth.getToken(),
}, },
contentType: "application/json; charset=utf-8", contentType: "application/json; charset=utf-8",
dataType: "json", dataType: "json",
complete: function (res, text) { complete: function (res, text) {
callback( callback(
text !== 'success' ? res.statusText : null, text !== "success" ? res.statusText : null,
JSON.parse(res.responseText), JSON.parse(res.responseText),
res.status res.status
) );
} },
}); });
} }
function get(url, callback) { function get(url, callback) {
$.ajax({ $.ajax({
type: 'GET', type: "GET",
url: baseURL + url, url: baseURL + url,
headers: { headers: {
'auth-token': app.auth.getToken() "auth-token": app.auth.getToken(),
}, },
contentType: "application/json; charset=utf-8", contentType: "application/json; charset=utf-8",
dataType: "json", dataType: "json",
complete: function (res, text) { complete: function (res, text) {
callback( callback(
text !== 'success' ? res.statusText : null, text !== "success" ? res.statusText : null,
JSON.parse(res.responseText), JSON.parse(res.responseText),
res.status res.status
) );
} },
}); });
} }
return {post: post, get: get, put: put, delete: remove} return { post: post, get: get, put: put, delete: remove };
})(app) })(app);
app.auth = (function (app) { app.auth = (function (app) {
var user = {} var user = {};
function setToken(token) { function setToken(token) {
localStorage.setItem('APIToken', token); localStorage.setItem("APIToken", token);
} }
function getToken() { function getToken() {
return localStorage.getItem('APIToken'); return localStorage.getItem("APIToken");
} }
function isLoggedIn(callback) { function isLoggedIn(callback) {
if (getToken()) { if (getToken()) {
return app.api.get('user/me', function(error, data){ return app.api.get("user/me", function (error, data) {
if (!error) app.auth.user = data; if (!error) app.auth.user = data;
return callback(error, data); return callback(error, data);
}); });
@ -108,7 +169,7 @@ app.auth = (function(app) {
} }
function logIn(args, callback) { function logIn(args, callback) {
app.api.post('auth/login', args, function(error, data){ app.api.post("auth/login", args, function (error, data) {
if (data.login) { if (data.login) {
setToken(data.token); setToken(data.token);
} }
@ -117,7 +178,7 @@ app.auth = (function(app) {
} }
function logOut(callback) { function logOut(callback) {
localStorage.removeItem('APIToken'); localStorage.removeItem("APIToken");
callback(); callback();
} }
@ -125,8 +186,8 @@ app.auth = (function(app) {
$.holdReady(true); $.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.href.replace(location.origin, '')}`); location.replace(`/login`);
} else { } else {
$.holdReady(false); $.holdReady(false);
} }
@ -134,7 +195,8 @@ app.auth = (function(app) {
} }
function logInRedirect() { function logInRedirect() {
window.location.href = location.href.replace(location.origin+'/login', '') || '/' window.location.href =
location.href.replace(location.replace(`/login`)) || "/";
} }
return { return {
@ -145,8 +207,7 @@ app.auth = (function(app) {
logOut: logOut, logOut: logOut,
forceLogin, forceLogin,
logInRedirect, logInRedirect,
} };
})(app); })(app);
//ajax form submit //ajax form submit
@ -167,12 +228,14 @@ function formAJAX( btn, del ) {
'info' 'info'
); );
//console.log('Data being sent to', $form.attr('action'), formData)
app.api[method]($form.attr('action'), formData, function(error, data){ app.api[method]($form.attr('action'), formData, function(error, data){
//console.log('Data back from the server', error, data)
app.util.actionMessage(data.message, $form, error ? 'danger' : 'success'); //re-populate table app.util.actionMessage(data.message, $form, error ? 'danger' : 'success'); //re-populate table
if(!error){ if(!error){
$form.trigger("reset"); $form.trigger("reset");
eval($form.attr('evalAJAX')); //gets JS to run after completion eval($form.attr('evalAJAX')); //gets JS to run after completion
} }
}); });
} }

View File

@ -1,58 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Login & Signup Form</title>
<link rel="stylesheet" href="css/sp.css" />
</head>
<body>
<section class="wrapper">
<div class="form signup">
<header>Signup</header>
<form action="routes/user.js/register" method="get">
<input type="text" id="username" placeholder="Username" required />
<input type="text" id="email" placeholder="Email" required />
<input type="text" id="address" placeholder="Address" required />
<input type="text" id="phone" placeholder="Phone Number" required />
<input type="password" id="password" placeholder="Password" required />
<input type="password" id="confirmPassword" placeholder="Confirm Password" required />
<div class="checkbox">
<input type="checkbox" id="signupCheck" />
<label for="signupCheck">I accept all terms & conditions</label>
</div>
<input type="submit" onclick="validateFormSignup()" value="Signup" />
</form>
</div>
<div class="form login">
<header>Login</header>
<form action="#">
<input type="text" id="email" placeholder="Email address" required />
<input type="password" id="password" placeholder="Password" required />
<a href="forgotpassword.html">Forgot password?</a>
<input type="submit" onclick="validateFormLogin()" value="Login" />
</form>
</div>
<script>
const wrapper = document.querySelector(".wrapper"),
signupHeader = document.querySelector(".signup header"),
loginHeader = document.querySelector(".login header");
loginHeader.addEventListener("click", () => {
wrapper.classList.add("active");
});
signupHeader.addEventListener("click", () => {
wrapper.classList.remove("active");
});
</script>
</section>
<script src="js/signup.js"></script>
<script src="js/login.js"></script>
</body>
</html>

View File

@ -51,6 +51,11 @@ router.get('/news', function(req, res, next) {
res.render('news'); res.render('news');
}); });
//login / register page
router.get('/login', function(req, res, next) {
res.render('signuplogin');
});
//404 page //404 page
router.get('*', function(req, res, next) { router.get('*', function(req, res, next) {
res.render('404'); res.render('404');

View File

@ -18,8 +18,9 @@ router.get("/", async (req, res, next) => {
// /user/register // /user/register
router.post("/register", async (req, res, next) => { router.post("/register", async (req, res, next) => {
try { try {
//await addUser(req.body); console.log("this is " , req.body);
res.sendStatus(200); await addUser(req.body);
res.status(200).json({ register: true });
} catch (error) { } catch (error) {
console.error(error); console.error(error);
next(error); next(error);
@ -33,3 +34,48 @@ router.post("/register", async (req, res, next) => {
//getbyid //getbyid
module.exports = router; 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;
*/

View File

@ -0,0 +1,96 @@
<!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="">
<!-- Bootstrap core CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
<!-- Custom styles for this template -->
<link rel="stylesheet" href="css/sp.css" />
<!-- jQuery library -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"
integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
<!-- Bootstrap 5 JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL"
crossorigin="anonymous"></script>
<!-- jquery app.js -->
<script src="js/app.js"></script>
</head>
<body>
<!-- javascript function to check if user is auth -->
<!-- wait for DOC to be ready -->
<script>
$(document).ready(function () {
app.auth.isLoggedIn(function (error, data) {
if (data) {
$('#cl-logout-button').show();
$('#cl-profile-button').show();
$('#cl-login-button').hide();
} else {
$('#cl-login-button').show();
}
});
});
</script>
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-light top-nav fixed-top">
<div class="container">
<a class="navbar-brand" href="/">
<img src="images/logo.png" alt="logo" />
</a>
<button class="navbar-toggler" 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 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>
<!-- profile button -->
<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"
style="display: none;">
<i class="fas fa-sign-out"></i>
Profile
</a>
<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>
</ul>
</div>
</div>
</nav>
</body>
</html>

View File

@ -0,0 +1,53 @@
<%- include('logintop') %>
<body>
<section class="wrapper">
<div class="form signup" >
<!--<div class="form signup card" -->
<header>Signup</header>
<!-- Return message from api -->
<div class="actionMessage" style="display:none"></div>
<!-- localhost/api/v0/user/register -->
<!-- evalAjax Fires when status is returned -->
<form action="user/register" onsubmit="formAJAX(this)" evalAJAX="app.auth.logInRedirect();">
<input type="text" name="username" placeholder="Username" required />
<input type="text" name="email" placeholder="Email" required />
<input type="text" name="address" placeholder="Address" required />
<input type="text" name="phone" placeholder="Phone Number" required />
<input type="password" name="password" placeholder="Password" required />
<input type="password" name="confirmPassword" placeholder="Confirm Password" required />
<input type="submit" value="Signup" />
</form>
</div>
<div class="form login">
<header>Login</header>
<!-- Return message from api -->
<div class="actionMessage" style="display:none"></div>
<form action="user/login" onsubmit="formAJAX(this)" evalAJAX="app.auth.logInRedirect();">
<input type="text" id="email" placeholder="Email address" required />
<input type="password" id="password" placeholder="Password" required />
<a href="/resetPassword">Forgot password?</a>
<input type="submit" value="Login" />
</form>
</div>
<script>
const wrapper = document.querySelector(".wrapper"),
signupHeader = document.querySelector(".signup header"),
loginHeader = document.querySelector(".login header");
loginHeader.addEventListener("click", () => {
wrapper.classList.add("active");
});
signupHeader.addEventListener("click", () => {
wrapper.classList.remove("active");
});
</script>
</section>
</body>
</html>

View File

@ -8,7 +8,8 @@
<meta name="author" content=""> <meta name="author" content="">
<!-- Bootstrap core CSS --> <!-- Bootstrap core CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
<!-- Custom styles for this template --> <!-- Custom styles for this template -->
@ -17,11 +18,15 @@
<link href="css/learnmore.css" rel="stylesheet"> <link href="css/learnmore.css" rel="stylesheet">
<!-- 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"
integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script> integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
<!-- Bootstrap 5 JavaScript --> <!-- Bootstrap 5 JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL"
crossorigin="anonymous"></script>
<!-- jquery app.js --> <!-- jquery app.js -->
@ -38,6 +43,7 @@
app.auth.isLoggedIn(function (error, data) { app.auth.isLoggedIn(function (error, data) {
if (data) { if (data) {
$('#cl-logout-button').show(); $('#cl-logout-button').show();
$('#cl-profile-button').show();
$('#cl-login-button').hide(); $('#cl-login-button').hide();
} else { } else {
$('#cl-login-button').show(); $('#cl-login-button').show();
@ -67,16 +73,18 @@
<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"> <!-- profile button -->
<a class="nav-link" href="/profile">Profile</a>
</li>
<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"
style="display: none;">
<i class="fas fa-sign-out"></i>
Profile
</a>
<a id="cl-login-button" class="btn btn-outline-danger my-2 my-sm-0" <a id="cl-login-button" class="btn btn-outline-danger my-2 my-sm-0"
onclick="app.auth.forceLogin()" style="display: none;"> onclick="app.auth.forceLogin()" style="display: none;">
<i class="fas fa-sign-out"></i> <i class="fas fa-sign-out"></i>
Login Login
</a> </a>
<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>