From 65c29e2e83659a0d1b71b382e7be7c030cc90a21 Mon Sep 17 00:00:00 2001 From: Glenn de Haan Date: Mon, 14 Nov 2022 16:36:29 +0100 Subject: [PATCH] Implemented voucher types. Updated the README.md --- README.md | 32 +++++++++++++++++++++++++++++--- docker-compose.yml | 1 + modules/logo.js | 15 +++++++++++++++ modules/types.js | 20 ++++++++++++++++++++ modules/unifi.js | 5 +++-- server.js | 37 +++++++++++++++++++++++++++++-------- template/home.ejs | 20 +++++++++++++++++++- template/voucher.ejs | 5 ++++- 8 files changed, 120 insertions(+), 15 deletions(-) create mode 100644 modules/logo.js create mode 100644 modules/types.js diff --git a/README.md b/README.md index 1921a55..83bfaa2 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,14 @@ A small UniFi Voucher Site for simple voucher creation ## Structure - ES6 Javascript -- SCSS +- ExpressJS - Node UniFi -- Webpack +- Tailwind ## Development Usage - Install NodeJS 16.0 or higher. - Run `npm ci` in the root folder -- Run `npm start` in the root folder +- Run `npm start` & `npm run tailwind` in the root folder Then open up your favorite browser and go to http://localhost:3000/ @@ -25,6 +25,32 @@ Then open up your favorite browser and go to http://localhost:3000/ ## Docker - Code from master is build by Docker Hub - Builds can be pulled by using this command: `docker pull glenndehaan/unifi-voucher-site` +- An example docker compose file can be found below: +```yaml +version: '3' +services: + app: + image: glenndehaan/unifi-voucher-site + ports: + - "8081:3000" + environment: + # The IP address to your UniFi OS Console + UNIFI_IP: '192.168.1.1' + # The port of your UniFi OS Console, this could be 443 or 8443 + UNIFI_PORT: 443 + # The username of a local UniFi OS account + UNIFI_USERNAME: 'admin' + # The password of a local UniFi OS account + UNIFI_PASSWORD: 'password' + # The UniFi Site ID + UNIFI_SITE_ID: 'default' + # The 'password' used to log in to this voucher portal + SECURITY_CODE: '0000' + # Voucher Types, format: expiration in minutes (required),single-use or multi-use vouchers value - '0' is for multi-use - '1' is for single-use (optional),upload speed limit in kbps (optional),download speed limit in kbps (optional),data transfer limit in MB (optional) + # To skip a parameter just but nothing in between the comma's + # After a voucher type add a semicolon, after the semicolon you can start a new voucher type + VOUCHER_TYPES: '480,0,,,;' +``` ## License diff --git a/docker-compose.yml b/docker-compose.yml index 54424da..d61d69f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,3 +11,4 @@ services: UNIFI_PASSWORD: 'password' UNIFI_SITE_ID: 'default' SECURITY_CODE: '0000' + VOUCHER_TYPES: '480,0,,,;' diff --git a/modules/logo.js b/modules/logo.js new file mode 100644 index 0000000..69dff70 --- /dev/null +++ b/modules/logo.js @@ -0,0 +1,15 @@ +/** + * Output the ascii logo + */ +module.exports = () => { + console.log(` __ __ _ _______ _ __ __ `); + console.log(` / / / /___ (_) ____(_) | | / /___ __ _______/ /_ ___ _____`); + console.log(` / / / / __ \\/ / /_ / / | | / / __ \\/ / / / ___/ __ \\/ _ \\/ ___/`); + console.log(`/ /_/ / / / / / __/ / / | |/ / /_/ / /_/ / /__/ / / / __/ / `); + console.log(`\\____/_/ /_/_/_/ /_/ |___/\\____/\\__,_/\\___/_/ /_/\\___/_/ `); + console.log(''); + console.log(' UniFi Voucher '); + console.log(' By: Glenn de Haan '); + console.log(' https://github.com/glenndehaan/unifi-voucher-site '); + console.log(''); +} diff --git a/modules/types.js b/modules/types.js new file mode 100644 index 0000000..00a6d22 --- /dev/null +++ b/modules/types.js @@ -0,0 +1,20 @@ +/** + * Returns an array or object of voucher type(s) + * + * @param string + * @param single + * @returns {*} + */ +module.exports = (string, single = false) => { + if(single) { + const match = string.match(/^(?\d+)?,(?\d+)?,(?\d+)?,(?\d+)?,(?\d+)?/); + return match.groups.expiration ? {...match.groups, raw: string} : undefined; + } + + const types = string.split(';'); + + return types.filter(n => n).map((type) => { + const match = type.match(/^(?\d+)?,(?\d+)?,(?\d+)?,(?\d+)?,(?\d+)?/); + return match.groups.expiration ? {...match.groups, raw: type} : undefined; + }).filter(n => n); +} diff --git a/modules/unifi.js b/modules/unifi.js index eb393ea..b488cea 100644 --- a/modules/unifi.js +++ b/modules/unifi.js @@ -26,13 +26,14 @@ const controller = new unifi.Controller({host: config.unifi.ip, port: config.uni /** * Exports the UniFi voucher function * + * @param type * @returns {Promise} */ -module.exports = () => { +module.exports = (type) => { return new Promise((resolve) => { controller.login(config.unifi.username, config.unifi.password).then(() => { controller.getSitesStats().then(() => { - controller.createVouchers(480).then((voucher_data) => { + controller.createVouchers(type.expiration, 1, type.usage === 1 ? 1 : 0, null, typeof type.upload !== "undefined" ? type.upload : null, typeof type.download !== "undefined" ? type.download : null, typeof type.megabytes !== "undefined" ? type.megabytes : null).then((voucher_data) => { controller.getVouchers(voucher_data[0].create_time).then((voucher_data_complete) => { const voucher = `${[voucher_data_complete[0].code.slice(0, 5), '-', voucher_data_complete[0].code.slice(5)].join('')}`; resolve(voucher); diff --git a/server.js b/server.js index 428db95..082cc26 100644 --- a/server.js +++ b/server.js @@ -9,12 +9,33 @@ const app = express(); /** * Import own modules */ +const logo = require('./modules/logo'); +const types = require('./modules/types'); const unifi = require('./modules/unifi'); /** - * Define global functions + * Define global functions and variables */ const random = (min, max) => Math.floor(Math.random() * (max - min)) + min; +const voucherTypes = types(process.env.VOUCHER_TYPES || '480,0,,,;'); + +/** + * Output logo + */ +logo(); + +/** + * Log voucher types + */ +console.log('[VoucherType] Loaded the following types:'); +voucherTypes.forEach((type, key) => { + console.log(`[VoucherType][${key}] ${type.expiration} minutes, ${type.usage === '1' ? 'single-use' : 'multi-use'}${typeof type.upload === "undefined" && typeof type.download === "undefined" && typeof type.megabytes === "undefined" ? ', no limits' : `${typeof type.upload !== "undefined" ? `, upload bandwidth limit: ${type.upload} kb/s` : ''}${typeof type.download !== "undefined" ? `, download bandwidth limit: ${type.download} kb/s` : ''}${typeof type.megabytes !== "undefined" ? `, quota limit: ${type.megabytes} mb` : ''}`}`); +}); + +/** + * Log controller + */ +console.log(`[UniFi] Using Controller on: ${process.env.UNIFI_IP || '192.168.1.1'}:${process.env.UNIFI_PORT || 443} (Site ID: ${process.env.UNIFI_SITE_ID || 'default'})`); /** * Trust proxy @@ -36,7 +57,7 @@ app.use(multer().none()); * Request logger */ app.use((req, res, next) => { - console.log(`[Web][REQUEST]: ${req.originalUrl}`); + console.log(`[Web]: ${req.originalUrl}`); next(); }); @@ -57,7 +78,8 @@ app.get('/', (req, res) => { error_text: req.query.error || '', banner_image: process.env.BANNER_IMAGE || `/images/bg-${random(1, 10)}.jpg`, app_header: timeHeader, - sid: uuidv4() + sid: uuidv4(), + voucher_types: voucherTypes }); }); app.post('/', async (req, res) => { @@ -68,7 +90,7 @@ app.post('/', async (req, res) => { return; } - res.redirect(encodeURI(`/voucher?code=${req.body.password}`)); + res.redirect(encodeURI(`/voucher?code=${req.body.password}&type=${req.body['voucher-type']}`)); }); app.get('/voucher', async (req, res) => { if(req.query.code !== (process.env.SECURITY_CODE || "0000")) { @@ -78,9 +100,7 @@ app.get('/voucher', async (req, res) => { const hour = new Date().getHours(); const timeHeader = hour < 12 ? 'Good Morning' : hour < 18 ? 'Good Afternoon' : 'Good Evening'; - const voucherCode = await unifi(); - - console.log(voucherCode); + const voucherCode = await unifi(types(req.query.type, true)); res.render('voucher', { error: typeof req.query.error === 'string' && req.query.error !== '', @@ -88,6 +108,7 @@ app.get('/voucher', async (req, res) => { banner_image: process.env.BANNER_IMAGE || `/images/bg-${random(1, 10)}.jpg`, app_header: timeHeader, code: req.query.code, + type: req.query.type, voucher_code: voucherCode, sid: uuidv4() }); @@ -110,5 +131,5 @@ app.disable('x-powered-by'); * Start listening on port */ app.listen(3000, '0.0.0.0', () => { - console.log(`App is running on: 0.0.0.0:3000`); + console.log(`[App] Running on: 0.0.0.0:3000`); }); diff --git a/template/home.ejs b/template/home.ejs index 0000cbb..5ada93e 100644 --- a/template/home.ejs +++ b/template/home.ejs @@ -30,7 +30,9 @@
- + + UniFi Logo +
@@ -49,6 +51,22 @@
+
+ +
+ +
+ + + +
+
+
+
diff --git a/template/voucher.ejs b/template/voucher.ejs index b6d3790..d5b7da4 100644 --- a/template/voucher.ejs +++ b/template/voucher.ejs @@ -30,7 +30,9 @@
- + + UniFi Logo +
@@ -45,6 +47,7 @@
+