Files
shop-ejs-expressjs/index.js
2022-03-29 21:08:51 +02:00

514 lines
18 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Import Packages
const express = require('express');
const bcrypt = require("bcryptjs");
const cookieParser = require("cookie-parser");
const jwt = require("jsonwebtoken");
const bodyParser = require("body-parser");
const uuid = require("uuid");
// Import Modules
const mysql_handler = require("./mysql_handler");
const validators = require("./validators")
// Global Variables
const app = express();
const port = 3000;
const SECRET_KEY = "KEY";
// Express App Setup
app.set("view engine", "ejs");
app.use(express.json());
app.use(express.urlencoded({ extended: true}));
app.use(cookieParser());
app.use(bodyParser.json());
app.use(express.static(__dirname + "/static"));
// Authentication Handlers
// Check if user is authenticated and NO redirect
function authNoRedirectHandler(req, res, next){
const authcookie = req.cookies.authcookie; // Get authcookie from cookie
jwt.verify(authcookie, SECRET_KEY, (err, data) =>{ // Verify authcookie
if(err){ // If authcookie is invalid
console.log(err);
next();
} else if(data.user){ // If authcookie is valid
req.user = data.user; // Set user to data.user
mysql_handler.con.query(`SELECT * FROM users WHERE id = "${req.user}"`, (err, result) => { // Get user from database
if(err) console.log(err);
let user = JSON.parse(JSON.stringify(result))[0]; // Parse user from database
if(user.id){
// Set user to req.user
req.isAdmin = user.isAdmin;
req.username = user.username;
req.firstname = user.firstname;
req.lastname = user.lastname;
req.email = user.email;
}
next(); // Continue to next handler
});
}
});
}
// Check if user is authenticated and redirect to login if not
function authenticatedHandler(req, res, next){
const authcookie = req.cookies.authcookie; // Get authcookie from cookie
jwt.verify(authcookie, SECRET_KEY, (err, data) =>{ // Verify authcookie
if(err){ // If authcookie is invalid
console.log(err);
res.redirect("/login");
} else if(data.user){ // If authcookie is valid
req.user = data.user; // Set user to data.user
mysql_handler.con.query(`SELECT * FROM users LEFT JOIN userinfos ON users.id=userinfos.userId WHERE users.id = "${req.user}"`, (err, result) => { // Get user from database
if(err) console.log(err);
let user = JSON.parse(JSON.stringify(result))[0]; // Parse user from database
// Set user to req.user
req.isAdmin = user.isAdmin;
req.username = user.username;
req.firstname = user.firstname;
req.lastname = user.lastname;
req.email = user.email;
next(); // Continue to next handler
});
}
});
}
// Check if user is not authenticated and redirect to home if so
function notAuthenticatedHandler(req, res, next){
const authcookie = req.cookies.authcookie; // Get authcookie from cookie
if(authcookie){
jwt.verify(authcookie, SECRET_KEY, (err, data) =>{ // Verify authcookie
if(err){ // If authcookie is invalid
console.log(err);
next(); // Continue to next handler
} else if(data.user){ // If authcookie is valid
res.redirect("/");
}
});
}else{
next();
}
}
// Homepage
app.get("/", authNoRedirectHandler, (req, res) => {
mysql_handler.con.query("SELECT * FROM products", function(err, result){
if(err) throw err;
let dict = {
title: "Startseite",
user: req.user,
products: JSON.parse(JSON.stringify(result))
}
res.render('index', dict)
});
});
// Account
app.get("/account", authenticatedHandler, (req, res) => {
mysql_handler.con.query(`SELECT orders.id, products.name, order_products.quantity, order_products.price
FROM orders LEFT JOIN order_products ON orders.id=order_products.orderId
LEFT JOIN products ON order_products.productId=products.id WHERE orders.userId = '${req.user}' ORDER BY orders.id DESC`, (err, result) => {
if(err) console.log(err);
let dict = {
title: "Account",
user: req.user,
isAdmin: req.isAdmin,
username: req.username,
firstname: req.firstname,
lastname: req.lastname,
email: req.email,
orders: JSON.parse(JSON.stringify(result))
}
res.render('account', dict)
})
});
// Product Page
app.get("/product/:productId", authNoRedirectHandler, (req, res) => {
let productId = req.params.productId;
mysql_handler.con.query(`SELECT s.name AS sellerName, p.name AS productName, p.description AS productDescription, p.id AS id, price,quantity, delivery_time, p.categoryId
FROM products AS p LEFT JOIN sellers AS s ON p.sellerId= s.id WHERE p.id=${productId}` , function(err, result){
if(err) throw err;
let product = JSON.parse(JSON.stringify(result))[0];
mysql_handler.con.query(`SELECT title, content ,rating, u.username AS name FROM reviews AS r LEFT JOIN users AS u ON r.userId = u.id WHERE productId=${productId}`,function(err,result){
if(err) throw err;
let reviews = JSON.parse(JSON.stringify(result));
console.log(product)
mysql_handler.con.query(`SELECT * FROM categories WHERE id='${product.categoryId}'`,function(err,result){
if(err) throw err;
let category = JSON.parse(JSON.stringify(result))[0];
let dict = {
title: product.productName,
product: product,
shippingDays: 3,
stockAmount: 50,
productDescription: "ez",
loggedIn: true,
reviews: reviews,
category: category,
user: req.user,
}
res.render('product', dict)
});
});
});
});
// Reviews
app.post("/review/create/:productId", authenticatedHandler,(req, res) => {
let productId = req.params.productId;
let rating = req.body.rating;
let title = req.body.title;
let content = req.body.content;
mysql_handler.con.query(`INSERT INTO reviews(title, content, rating, userId, productId)
VALUES('${title}', '${content}', '${rating}', (SELECT id FROM users WHERE id = ${req.user}), (SELECT id FROM products WHERE id = ${productId}))`, (err, result) => {
if(err) throw err;
res.redirect("/product/" + productId);
});
});
// Search Page
app.get("/search", authNoRedirectHandler,(req, res) => {
var products = [
{
title: "Panasonic LUMIX DC-GH5M2ME",
price: 1699.99,
img: "https://m.media-amazon.com/images/I/815eDw--FQS._AC_SL1500_.jpg",
desc: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.",
},
{
title: "Sony α 7 IV",
price: 2999.00,
img: "https://m.media-amazon.com/images/I/819+EOCsREL._AC_SL1500_.jpg",
desc: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.",
},
{
title: "Canon PowerShot G3 X",
price: 876.34,
img: "https://m.media-amazon.com/images/I/91bODLikNBL._AC_SL1500_.jpg",
desc: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.",
},
{
title: "Canon PowerShot SX710",
price: 495.00,
img: "https://m.media-amazon.com/images/I/91w6iw3JtiL._AC_SL1500_.jpg",
desc: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.",
},
]
let dict = {
title: "Suche",
products: products,
user: req.user,
}
mysql_handler.con.query("SELECT * FROM products", function(err, result){
if(err) throw err;
dict.products = JSON.parse(JSON.stringify(result));
res.render('search', dict)
});
});
// Order Page
app.get("/order/:productId/:quantity/", authenticatedHandler, (req, res) => {
let error = "";
mysql_handler.con.query(`SELECT * FROM products WHERE id=${req.params.productId}`, function(err, result){ // Get product from database
if(err) throw err;
result = JSON.parse(JSON.stringify(result))[0]; // Parse result from database
if(req.params.quantity > result.quantity){ // If quantity is higher than available quantity
error = "Nicht genug Produkte vorhanden";
}
let dict = {
title: "Bestellung",
error: error,
product: result,
quantity: req.params.quantity,
user: req.user,
}
res.render('order', dict);
});
});
// Order Success Page
app.get("/order_success/:trackingnumber", authenticatedHandler, (req, res) => {
let dict = {
title: "Bestellung erfolgreich",
trackingnumber: req.params.trackingnumber
}
res.render('order_success', dict);
});
// Order POST Request
app.post("/order", authenticatedHandler, (req, res) => {
let productId = req.body.productId;
let quantity = req.body.quantity;
let userId = req.user;
mysql_handler.con.query(`SELECT * FROM products WHERE id=${productId}`, function(err, result){
if(err) throw err;
result = JSON.parse(JSON.stringify(result))[0];
if(quantity > result.quantity){
res.redirect(`/order/${productId}/${quantity}/`);
}else{
order_trackingnumber = uuid.v4();
mysql_handler.createOrder(userId, order_trackingnumber, 0, productId, quantity) ;
res.redirect("/order_success/" + order_trackingnumber);
}
});
});
// Admin
app.get("/admin/product/delete/:productId", authenticatedHandler, (req, res) => {
if(req.isAdmin){
productId = req.params.productId;
mysql_handler.con.query(`DELETE FROM products WHERE id=${productId}`, function(err, result){
if(err) console.log(err);
});
}
});
// Authentication
// Logout
app.get("/logout/", authenticatedHandler, (req, res) => {
res.clearCookie("authcookie"); // Clear cookie
res.redirect("/");
});
// Register Page
app.get("/register/:error?", notAuthenticatedHandler, (req, res) => {
let dict = {
title: "Register",
error: req.params.error
}
res.render('register', dict);
});
// Login Page
app.get("/login/:error?", notAuthenticatedHandler, (req, res) => {
let dict = {
title: "Login",
error: req.params.error
}
res.render('login', dict);
});
// Register POST Request
app.post("/auth/register", notAuthenticatedHandler, (req, res) =>{
// Get data from POST request
let username = req.body.username;
let email = req.body.email;
let password1 = req.body.password1;
let password2 = req.body.password2;
let firstname = req.body.firstname;
let lastname = req.body.lastname;
let gender = req.body.gender;
let street = req.body.street;
let housenumber = req.body.housenumber;
let postcode = req.body.postcode;
let city = req.body.city;
let country = req.body.country;
let error = false;
/*
0: No error
error_username_duplicate: Username already exists
error_email_duplicate: Email already exists
error_password_length_short: Password is too short
error_password_length_long: Password is too long
error_password_mismatch: Passwords do not match
error_password_invalid
error_email_invalid
error_username_invalid
error_firstname_invalid
error_lastname_invalid
error_street_invalid
error_housenumber_invalid
error_postcode_invalid
error_cityname_invalid
error_country_invalid
*/
validateUsername = validators.validate_username(username);
if(validateUsername != 0){
console.log(validateUsername);
res.send(validateUsername);
return;
}
validateEmail = validators.validate_email(email);
if(validateEmail != 0){
console.log(validateEmail);
res.send(validateEmail);
return;
}
validatePasswords = validators.validate_passwords(password1, password2);
if(validatePasswords != 0){
console.log(validatePasswords);
res.send(validatePasswords);
return;
}
validateFirstname = validators.validate_firstname(firstname);
if(validateFirstname != 0){
console.log(validateFirstname);
res.send(validateFirstname);
return;
}
validateLastname = validators.validate_lastname(lastname);
if(validateLastname != 0){
console.log(validateLastname);
res.send(validateLastname);
return;
}
validateGender = validators.validate_gender(gender);
if(validateGender != 0){
console.log(validateGender);
res.send(validateGender);
return;
}
validateStreet = validators.validate_street(street);
if(validateStreet != 0){
console.log(validateStreet);
res.send(validateStreet);
return;
}
validateHousenumber = validators.validate_housenumber(housenumber);
if(validateHousenumber != 0){
console.log(validateHousenumber);
res.send(validateHousenumber);
return;
}
validatePostcode = validators.validate_postcode(postcode);
if(validatePostcode != 0){
console.log(validatePostcode);
res.send(validatePostcode);
return;
}
validateCity = validators.validate_city(city);
if(validateCity != 0){
console.log(validateCity);
res.send(validateCity);
return;
}
validateCountry = validators.validate_country(country);
if(validateCountry != 0){
console.log(validateCountry);
res.send(validateCountry);
return;
}
// CHECK DUPLICATES
// Check email duplicate
mysql_handler.con.query(`SELECT * FROM users WHERE email='${email}'`, (err, result) => {
if(err) console.log(err);
if(result.length > 0){
res.send("error_email_duplicate");
}else{
// Check username duplicate
mysql_handler.con.query(`SELECT * FROM users WHERE username='${username}'`, (err, result) => {
if(err) console.log(err);
if(result.length > 0){
res.send("error_username_duplicate");
}else{
// NO duplicates
bcrypt.genSalt(10, function(err, salt) { // Generate salt
bcrypt.hash(password1, salt, function(err, hash){ // Hash password
console.log("create");
mysql_handler.createUser(username, email, hash, firstname, lastname, gender, street, housenumber, postcode, city, country);
res.send("0");
});
});
}
})
}
});
});
// Login POST Request
app.post("/auth/login", notAuthenticatedHandler, (req, res) =>{
// Get data from POST request
let username = req.body.username;
let password = req.body.password;
error = "" // Error message
mysql_handler.con.query(`SELECT * FROM users WHERE username = "${username}"`, function(err, result){ // Get user from database
if(err){ // If there is an error
error = "Login-Daten falsch!"
}else{ // If there is no error
result = JSON.parse(JSON.stringify(result))[0]; // Parse result from database
if(result){ // If there is a user
user = result; // Set user
dbPassword = user.password; // Get password from database
bcrypt.compare(password, dbPassword, function(err, matched){ // Compare password
if(err) console.log(err);
if(matched){ // If password matches
// Set cookie
const token = jwt.sign({user:user.id}, SECRET_KEY)
res.cookie('authcookie', token, {maxAge: 90000000, httpOnly: true})
res.redirect(`/`)
}else{
error = "Login-Daten falsch!"
}
})
}else{
error = "Login-Daten falsch!"
}
}
if(error != ""){ // If there is an error
res.redirect(`/login/${error}`)
}
});
})
app.listen(port, () =>{ // Start server
console.log("Listining to " + port)
});