Compare commits
2 Commits
7d8ed6d0ee
...
001e4b6d00
| Author | SHA1 | Date | |
|---|---|---|---|
| 001e4b6d00 | |||
| 825583e645 |
+17
-15
@@ -1,11 +1,12 @@
|
||||
var createError = require('http-errors');
|
||||
var express = require('express');
|
||||
var path = require('path');
|
||||
var cookieParser = require('cookie-parser');
|
||||
var logger = require('morgan');
|
||||
var createError = require("http-errors");
|
||||
var express = require("express");
|
||||
var path = require("path");
|
||||
var cookieParser = require("cookie-parser");
|
||||
var logger = require("morgan");
|
||||
|
||||
var indexRouter = require('./routes/index');
|
||||
var usersRouter = require('./routes/users');
|
||||
var indexRouter = require("./routes/index");
|
||||
var usersRouter = require("./routes/users");
|
||||
const codeRouter = require("./routes/code");
|
||||
|
||||
const db = require("./models");
|
||||
var cors = require("cors");
|
||||
@@ -13,17 +14,18 @@ var cors = require("cors");
|
||||
var app = express();
|
||||
app.set("db", db);
|
||||
// view engine setup
|
||||
app.set('views', path.join(__dirname, 'views'));
|
||||
app.set('view engine', 'jade');
|
||||
app.set("views", path.join(__dirname, "views"));
|
||||
app.set("view engine", "jade");
|
||||
app.use(cors());
|
||||
app.use(logger('dev'));
|
||||
app.use(logger("dev"));
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: false }));
|
||||
app.use(cookieParser());
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
app.use(express.static(path.join(__dirname, "public")));
|
||||
|
||||
app.use('/', indexRouter);
|
||||
app.use('/users', usersRouter);
|
||||
app.use("/", indexRouter);
|
||||
app.use("/users", usersRouter);
|
||||
app.use("/api/v1/code", codeRouter);
|
||||
|
||||
// catch 404 and forward to error handler
|
||||
app.use(function (req, res, next) {
|
||||
@@ -34,11 +36,11 @@ app.use(function (req, res, next) {
|
||||
app.use(function (err, req, res, next) {
|
||||
// set locals, only providing error in development
|
||||
res.locals.message = err.message;
|
||||
res.locals.error = req.app.get('env') === 'development' ? err : {};
|
||||
res.locals.error = req.app.get("env") === "development" ? err : {};
|
||||
|
||||
// render the error page
|
||||
res.status(err.status || 500);
|
||||
res.render('error');
|
||||
res.render("error");
|
||||
});
|
||||
|
||||
module.exports = app;
|
||||
|
||||
+16
-19
@@ -4,16 +4,16 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var app = require('../app');
|
||||
var debug = require('debug')('day-1:server');
|
||||
var http = require('http');
|
||||
var app = require("../app");
|
||||
var debug = require("debug")("day-1:server");
|
||||
var http = require("http");
|
||||
|
||||
/**
|
||||
* Get port from environment and store in Express.
|
||||
*/
|
||||
|
||||
var port = normalizePort(process.env.PORT || '3000');
|
||||
app.set('port', port);
|
||||
var port = normalizePort(process.env.PORT || "3000");
|
||||
app.set("port", port);
|
||||
|
||||
/**
|
||||
* Create HTTP server.
|
||||
@@ -26,8 +26,8 @@ var server = http.createServer(app);
|
||||
*/
|
||||
|
||||
server.listen(port);
|
||||
server.on('error', onError);
|
||||
server.on('listening', onListening);
|
||||
server.on("error", onError);
|
||||
server.on("listening", onListening);
|
||||
|
||||
/**
|
||||
* Normalize a port into a number, string, or false.
|
||||
@@ -54,22 +54,20 @@ function normalizePort(val) {
|
||||
*/
|
||||
|
||||
function onError(error) {
|
||||
if (error.syscall !== 'listen') {
|
||||
if (error.syscall !== "listen") {
|
||||
throw error;
|
||||
}
|
||||
|
||||
var bind = typeof port === 'string'
|
||||
? 'Pipe ' + port
|
||||
: 'Port ' + port;
|
||||
var bind = typeof port === "string" ? "Pipe " + port : "Port " + port;
|
||||
|
||||
// handle specific listen errors with friendly messages
|
||||
switch (error.code) {
|
||||
case 'EACCES':
|
||||
console.error(bind + ' requires elevated privileges');
|
||||
case "EACCES":
|
||||
console.error(bind + " requires elevated privileges");
|
||||
process.exit(1);
|
||||
break;
|
||||
case 'EADDRINUSE':
|
||||
console.error(bind + ' is already in use');
|
||||
case "EADDRINUSE":
|
||||
console.error(bind + " is already in use");
|
||||
process.exit(1);
|
||||
break;
|
||||
default:
|
||||
@@ -83,8 +81,7 @@ function onError(error) {
|
||||
|
||||
function onListening() {
|
||||
var addr = server.address();
|
||||
var bind = typeof addr === 'string'
|
||||
? 'pipe ' + addr
|
||||
: 'port ' + addr.port;
|
||||
debug('Listening on ' + bind);
|
||||
var bind = typeof addr === "string" ? "pipe " + addr : "port " + addr.port;
|
||||
debug("Listening on " + bind);
|
||||
console.log("Server listening on:", bind);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>A simple, clean, and responsive HTML invoice template</title>
|
||||
|
||||
<style>
|
||||
.invoice-box {
|
||||
max-width: 800px;
|
||||
margin: auto;
|
||||
padding: 30px;
|
||||
border: 1px solid #eee;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.invoice-box table {
|
||||
width: 100%;
|
||||
line-height: inherit;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.invoice-box table td {
|
||||
padding: 5px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.invoice-box table tr td:nth-child(2) {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.invoice-box table tr.top table td {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.invoice-box table tr.top table td.title {
|
||||
font-size: 45px;
|
||||
line-height: 45px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.invoice-box table tr.information table td {
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
.invoice-box table tr.heading td {
|
||||
background: #eee;
|
||||
border-bottom: 1px solid #ddd;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.invoice-box table tr.details td {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.invoice-box table tr.item td {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.invoice-box table tr.item.last td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.invoice-box table tr.total td:nth-child(2) {
|
||||
border-top: 2px solid #eee;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 600px) {
|
||||
.invoice-box table tr.top table td {
|
||||
width: 100%;
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.invoice-box table tr.information table td {
|
||||
width: 100%;
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
/** RTL **/
|
||||
.invoice-box.rtl {
|
||||
direction: rtl;
|
||||
font-family: Tahoma, "Helvetica Neue", "Helvetica", Helvetica, Arial,
|
||||
sans-serif;
|
||||
}
|
||||
|
||||
.invoice-box.rtl table {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.invoice-box.rtl table tr td:nth-child(2) {
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="invoice-box">
|
||||
<table cellpadding="0" cellspacing="0">
|
||||
<tr class="top">
|
||||
<td colspan="2">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="title">
|
||||
<img
|
||||
src="https://sparksuite.github.io/simple-html-invoice-template/images/logo.png"
|
||||
style="width: 100%; max-width: 300px"
|
||||
/>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Invoice #: 123<br />
|
||||
Created: January 1, 2023<br />
|
||||
Due: February 1, 2023
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="information">
|
||||
<td colspan="2">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
Sparksuite, Inc.<br />
|
||||
12345 Sunny Road<br />
|
||||
Sunnyville, CA 12345
|
||||
</td>
|
||||
|
||||
<td>
|
||||
Acme Corp.<br />
|
||||
John Doe<br />
|
||||
john@example.com
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="heading">
|
||||
<td>Payment Method</td>
|
||||
|
||||
<td>Check #</td>
|
||||
</tr>
|
||||
|
||||
<tr class="details">
|
||||
<td>Check</td>
|
||||
|
||||
<td>1000</td>
|
||||
</tr>
|
||||
|
||||
<tr class="heading">
|
||||
<td>Item</td>
|
||||
|
||||
<td>Price</td>
|
||||
</tr>
|
||||
|
||||
<tr class="item last">
|
||||
<td>Website design</td>
|
||||
|
||||
<td>$300.00</td>
|
||||
</tr>
|
||||
|
||||
<!-- <tr class="item">
|
||||
<td>Hosting (3 months)</td>
|
||||
|
||||
<td>$75.00</td>
|
||||
</tr>
|
||||
|
||||
<tr class="item last">
|
||||
<td>Domain name (1 year)</td>
|
||||
|
||||
<td>$10.00</td>
|
||||
</tr> -->
|
||||
|
||||
<tr class="total">
|
||||
<td></td>
|
||||
|
||||
<td>Total: $385.00</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
+5
-1
@@ -3,18 +3,22 @@
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "node ./bin/www"
|
||||
"start": "node ./bin/www",
|
||||
"dev": "node --watch --env-file=.env ./bin/www"
|
||||
},
|
||||
"dependencies": {
|
||||
"cookie-parser": "~1.4.4",
|
||||
"cors": "^2.8.5",
|
||||
"debug": "~2.6.9",
|
||||
"express": "~4.16.1",
|
||||
"html-pdf-node": "^1.0.8",
|
||||
"http-errors": "~1.6.3",
|
||||
"jade": "~1.11.0",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"morgan": "~1.9.1",
|
||||
"mysql2": "^2.3.3",
|
||||
"node-input-validator": "^4.5.1",
|
||||
"qrcode": "^1.5.4",
|
||||
"sequelize": "^6.15.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const pdf = require("html-pdf-node");
|
||||
|
||||
router.get("/:code", async (req, res) => {
|
||||
const { amount = 1, service = "software service" } = req.query;
|
||||
|
||||
// Read the invoice template
|
||||
const templatePath = path.join(__dirname, "../invoice.html");
|
||||
let html = fs.readFileSync(templatePath, "utf8");
|
||||
|
||||
// Replace placeholders in the template
|
||||
html = html
|
||||
.replace("Website design", service)
|
||||
.replace("$300.00", `$${amount}.00`)
|
||||
.replace("Total: $385.00", `Total: $${amount}.00`);
|
||||
|
||||
// Generate PDF
|
||||
let file = { content: html };
|
||||
pdf.generatePdf(file, { format: "A4" }).then((pdfBuffer) => {
|
||||
res.setHeader("Content-Type", "application/pdf");
|
||||
res.setHeader("Content-Disposition", "attachment; filename=invoice.pdf");
|
||||
res.send(pdfBuffer);
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
+16
-3
@@ -1,9 +1,22 @@
|
||||
var express = require('express');
|
||||
var express = require("express");
|
||||
var router = express.Router();
|
||||
const QRCode = require("qrcode");
|
||||
|
||||
/* GET home page. */
|
||||
router.get('/', function(req, res, next) {
|
||||
res.render('index', { title: 'Express' });
|
||||
router.get("/", function (req, res, next) {
|
||||
res.render("index", { title: "Express" });
|
||||
});
|
||||
|
||||
router.get("/code", async function (req, res, next) {
|
||||
const code = Math.random().toString(36).substring(2, 8); // random code
|
||||
const qrUrl = `/api/v1/code/${code}?amount=1&service=software%20service`;
|
||||
const qrData = await QRCode.toDataURL(
|
||||
`http://localhost:${process.env.PORT || 3000}${qrUrl}`
|
||||
);
|
||||
res.render("code", {
|
||||
qrData,
|
||||
qrUrl: `http://localhost:${process.env.PORT || 3000}${qrUrl}`,
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
extends layout
|
||||
|
||||
block content
|
||||
h1 QR Code
|
||||
img(src=qrData)
|
||||
p Link: #{qrUrl}
|
||||
+23
-16
@@ -1,29 +1,33 @@
|
||||
var createError = require('http-errors');
|
||||
var express = require('express');
|
||||
var path = require('path');
|
||||
var cookieParser = require('cookie-parser');
|
||||
var logger = require('morgan');
|
||||
var createError = require("http-errors");
|
||||
var express = require("express");
|
||||
var path = require("path");
|
||||
var cookieParser = require("cookie-parser");
|
||||
var logger = require("morgan");
|
||||
|
||||
var indexRouter = require('./routes/index');
|
||||
var usersRouter = require('./routes/users');
|
||||
var indexRouter = require("./routes/index");
|
||||
var usersRouter = require("./routes/users");
|
||||
|
||||
const db = require("./models");
|
||||
var cors = require("cors");
|
||||
const maintenanceMiddleware = require("./middleware/Maintenance");
|
||||
const roleCheckMiddleware = require("./middleware/RoleCheckMiddleware");
|
||||
|
||||
var app = express();
|
||||
app.set("db", db);
|
||||
// view engine setup
|
||||
app.set('views', path.join(__dirname, 'views'));
|
||||
app.set('view engine', 'jade');
|
||||
app.set("views", path.join(__dirname, "views"));
|
||||
app.set("view engine", "jade");
|
||||
app.use(cors());
|
||||
app.use(logger('dev'));
|
||||
app.use(logger("dev"));
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: false }));
|
||||
app.use(cookieParser());
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
app.use(express.static(path.join(__dirname, "public")));
|
||||
app.use(maintenanceMiddleware);
|
||||
app.use("/api/v1", roleCheckMiddleware);
|
||||
|
||||
app.use('/', indexRouter);
|
||||
app.use('/users', usersRouter);
|
||||
app.use("/", indexRouter);
|
||||
app.use("/users", usersRouter);
|
||||
|
||||
// catch 404 and forward to error handler
|
||||
app.use(function (req, res, next) {
|
||||
@@ -34,11 +38,14 @@ app.use(function (req, res, next) {
|
||||
app.use(function (err, req, res, next) {
|
||||
// set locals, only providing error in development
|
||||
res.locals.message = err.message;
|
||||
res.locals.error = req.app.get('env') === 'development' ? err : {};
|
||||
res.locals.error = req.app.get("env") === "development" ? err : {};
|
||||
|
||||
// render the error page
|
||||
// standardized error response
|
||||
res.status(err.status || 500);
|
||||
res.render('error');
|
||||
res.json({
|
||||
success: false,
|
||||
error: err.message || "Internal Server Error",
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = app;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
maintenance: false,
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
const JwtService = require("../services/JwtService");
|
||||
|
||||
module.exports = function (req, res, next) {
|
||||
const token = JwtService.getToken(req);
|
||||
if (!token) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: "Access denied. No token provided.",
|
||||
});
|
||||
}
|
||||
const payload = JwtService.verifyAccessToken(token);
|
||||
if (!payload) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: "Invalid or expired token.",
|
||||
});
|
||||
}
|
||||
req.tokenPayload = payload;
|
||||
if (payload && payload.user_id) {
|
||||
req.user_id = payload.user_id;
|
||||
}
|
||||
next();
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
const config = require("../config");
|
||||
|
||||
module.exports = function (req, res, next) {
|
||||
if (config.maintenance) {
|
||||
return res.status(503).json({
|
||||
success: false,
|
||||
error: "Service is under maintenance. Please try again later.",
|
||||
});
|
||||
}
|
||||
next();
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
module.exports = function (req, res, next) {
|
||||
const match = req.path.match(/^\/api\/v1\/(\w+)\//);
|
||||
if (match) {
|
||||
const portal = match[1];
|
||||
const userRole = req.tokenPayload && req.tokenPayload.role;
|
||||
if (userRole !== portal) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
error: `Access denied. Role '${userRole}' does not match portal '${portal}'.`,
|
||||
});
|
||||
}
|
||||
}
|
||||
next();
|
||||
};
|
||||
+2
-1
@@ -3,7 +3,8 @@
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "node ./bin/www"
|
||||
"start": "node ./bin/www",
|
||||
"dev": "node --watch ./bin/www"
|
||||
},
|
||||
"dependencies": {
|
||||
"cookie-parser": "~1.4.4",
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
var express = require('express');
|
||||
var express = require("express");
|
||||
var router = express.Router();
|
||||
const authMiddleware = require("../middleware/AuthMiddleware");
|
||||
|
||||
/* GET users listing. */
|
||||
router.get('/', function(req, res, next) {
|
||||
res.send('respond with a resource');
|
||||
router.get("/", authMiddleware, function (req, res, next) {
|
||||
res.json({
|
||||
success: true,
|
||||
data: "respond with a resource",
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
Reference in New Issue
Block a user