mirror of
https://github.com/glenndehaan/unifi-voucher-site.git
synced 2026-03-31 06:24:00 -04:00
Mayor V2 refactor. Now also available on DockerHub
This commit is contained in:
13
.dockerignore
Normal file
13
.dockerignore
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# PhpStorm
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# General files
|
||||||
|
*~
|
||||||
|
*.DS_STORE
|
||||||
|
|
||||||
|
# Dependency managers
|
||||||
|
node_modules/
|
||||||
|
npm-debug.log
|
||||||
|
|
||||||
|
# Build files
|
||||||
|
public/dist/
|
||||||
@@ -8,11 +8,6 @@ end_of_line = lf
|
|||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
# PHP PSR2 overrides
|
|
||||||
[*.php]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 4
|
|
||||||
|
|
||||||
# JS overrides
|
# JS overrides
|
||||||
[*.js]
|
[*.js]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
|
|||||||
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
@@ -1,3 +0,0 @@
|
|||||||
# These are supported funding model platforms
|
|
||||||
|
|
||||||
liberapay: glenndehaan
|
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -10,7 +10,4 @@ node_modules/
|
|||||||
npm-debug.log
|
npm-debug.log
|
||||||
|
|
||||||
# Build files
|
# Build files
|
||||||
dist/
|
public/dist/
|
||||||
|
|
||||||
# Project
|
|
||||||
app/config/config.js
|
|
||||||
|
|||||||
19
Dockerfile
Normal file
19
Dockerfile
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
FROM alpine:3.13
|
||||||
|
|
||||||
|
# Install packages
|
||||||
|
RUN apk add --no-cache nginx nodejs npm
|
||||||
|
|
||||||
|
# Create app directory
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
# Bundle app source
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Create production build
|
||||||
|
RUN npm ci --only=production && npm run build
|
||||||
|
|
||||||
|
# Expose app
|
||||||
|
EXPOSE 3001
|
||||||
|
|
||||||
|
# Run app
|
||||||
|
CMD ["node", "/usr/src/app/app/server.js"]
|
||||||
28
README.md
28
README.md
@@ -1,14 +1,30 @@
|
|||||||
# UniFi Voucher Site
|
# UniFi Voucher Site
|
||||||
|
|
||||||
## Usage
|
A small UniFi Voucher Site for simple voucher creation
|
||||||
|
|
||||||
|
[](https://hub.docker.com/r/glenndehaan/unifi-voucher-site) [](https://hub.docker.com/r/glenndehaan/unifi-voucher-site)
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
- ES6 Javascript
|
||||||
|
- SCSS
|
||||||
|
- Node UniFi
|
||||||
|
- Webpack
|
||||||
|
|
||||||
|
## Development Usage
|
||||||
- Install NodeJS 8.0 or higher.
|
- Install NodeJS 8.0 or higher.
|
||||||
- Copy the `config.sample.js` to `config.js` in the `app/config` folder
|
- Run `npm ci` in the root folder
|
||||||
- Change the `config.js` to your liking's and add your UniFi controller credentials
|
|
||||||
- Run `npm install` in the root folder
|
|
||||||
- Run `npm start` in the root folder
|
- Run `npm start` in the root folder
|
||||||
|
|
||||||
Then open up your favorite web browser and go to: http://localhost:3001
|
Then open up your favorite browser and go to http://localhost:3001/
|
||||||
That's it. Easy right?
|
|
||||||
|
## Build Usage
|
||||||
|
- Install NodeJS 8.0 or higher.
|
||||||
|
- Run `npm ci` in the root folder
|
||||||
|
- Run `npm run build` in the root folder
|
||||||
|
|
||||||
|
## Docker
|
||||||
|
- Code from master is build by Docker Hub
|
||||||
|
- Builds can be pulled by using this command: `docker pull glenndehaan/unifi-voucher-site`
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,16 @@
|
|||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const autoprefixer = require('autoprefixer');
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
|
||||||
const ManifestPlugin = require('webpack-manifest-plugin');
|
|
||||||
const browsers = require('../package.json').browserslist;
|
|
||||||
|
|
||||||
//Get path so every environment works
|
//Get path so every environment works
|
||||||
const projectPath = path.resolve(__dirname);
|
const projectPath = path.resolve(__dirname);
|
||||||
|
|
||||||
//Environment check depending on call from
|
//Environment check depending on call from
|
||||||
const env = process.env.NODE_ENV || 'development';
|
const env = process.env.NODE_ENV || 'development';
|
||||||
const isProd = env === 'production';
|
|
||||||
|
|
||||||
//Define all the global config for both production & dev
|
//Define all the global config for both production & dev
|
||||||
const config = {
|
module.exports = {
|
||||||
entry: {
|
entry: {
|
||||||
main: [
|
main: [
|
||||||
projectPath + '/../public/js/main.js',
|
projectPath + '/../public/js/main.js',
|
||||||
@@ -22,37 +19,30 @@ const config = {
|
|||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
path: projectPath + '/../public/dist/',
|
path: projectPath + '/../public/dist/',
|
||||||
filename: '[name].[hash:6].js'
|
filename: '[name].[fullhash:6].js',
|
||||||
|
publicPath: ''
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
loaders: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.js$/,
|
test: /\.js$/,
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
loader: 'babel-loader',
|
use: {
|
||||||
query: {
|
loader: 'babel-loader',
|
||||||
presets: ['babel-preset-es2015'].map(require.resolve),
|
options: {
|
||||||
sourceMaps: 'inline'
|
presets: [
|
||||||
|
require.resolve('@babel/preset-env')
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(css|scss)$/,
|
test: /\.scss$/,
|
||||||
loader: ExtractTextPlugin.extract({
|
use: [
|
||||||
use: [
|
MiniCssExtractPlugin.loader,
|
||||||
'raw-loader?url=false', {
|
'css-loader?url=false',
|
||||||
loader: 'postcss-loader',
|
'sass-loader'
|
||||||
options: {
|
]
|
||||||
ident: 'postcss',
|
|
||||||
context: path.resolve(__dirname, '../public'),
|
|
||||||
sourceMap: 'inline',
|
|
||||||
plugins: [
|
|
||||||
autoprefixer({browsers})
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'sass-loader?sourceMap=true'
|
|
||||||
]
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -62,8 +52,10 @@ const config = {
|
|||||||
NODE_ENV: JSON.stringify(env)
|
NODE_ENV: JSON.stringify(env)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
new ExtractTextPlugin({filename: 'main.[hash:6].css', allChunks: true}),
|
new MiniCssExtractPlugin({
|
||||||
new ManifestPlugin({
|
filename: '[name].[fullhash:6].css'
|
||||||
|
}),
|
||||||
|
new WebpackManifestPlugin({
|
||||||
fileName: 'rev-manifest.json'
|
fileName: 'rev-manifest.json'
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
@@ -72,33 +64,3 @@ const config = {
|
|||||||
modules: [path.join(__dirname, '../node_modules')]
|
modules: [path.join(__dirname, '../node_modules')]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//Extra options depending on environment
|
|
||||||
if (isProd) {
|
|
||||||
Object.assign(config, {
|
|
||||||
plugins: config.plugins.concat([
|
|
||||||
new webpack.LoaderOptionsPlugin({
|
|
||||||
minimize: true
|
|
||||||
}),
|
|
||||||
new webpack.optimize.UglifyJsPlugin({
|
|
||||||
drop_console: true,
|
|
||||||
output: {
|
|
||||||
comments: false
|
|
||||||
},
|
|
||||||
compressor: {
|
|
||||||
screw_ie8: true,
|
|
||||||
warnings: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
])
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Object.assign(config, {
|
|
||||||
devtool: 'cheap-module-eval-source-map',
|
|
||||||
plugins: config.plugins.concat([
|
|
||||||
new webpack.NoEmitOnErrorsPlugin()
|
|
||||||
])
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = config;
|
|
||||||
|
|||||||
22
app/config/config.js
Normal file
22
app/config/config.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* General config
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
application: {
|
||||||
|
name: "UniFi Voucher",
|
||||||
|
env: " (local)",
|
||||||
|
basePath: "/",
|
||||||
|
port: 3001,
|
||||||
|
bind: "0.0.0.0"
|
||||||
|
},
|
||||||
|
security: {
|
||||||
|
code: process.env.SECURITY_CODE || "0000" // <- Only 4 digits
|
||||||
|
},
|
||||||
|
unifi: {
|
||||||
|
ip: process.env.UNIFI_IP || '192.168.1.1',
|
||||||
|
port: process.env.UNIFI_PORT || 8443,
|
||||||
|
username: process.env.UNIFI_USERNAME || 'admin',
|
||||||
|
password: process.env.UNIFI_PASSWORD || 'password',
|
||||||
|
siteID: process.env.UNIFI_SITE_ID || 'default'
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
/**
|
|
||||||
* General config
|
|
||||||
*/
|
|
||||||
const config = {
|
|
||||||
application: {
|
|
||||||
name: "UniFi Voucher",
|
|
||||||
env: " (local)",
|
|
||||||
basePath: "/",
|
|
||||||
port: 3001,
|
|
||||||
bind: "0.0.0.0",
|
|
||||||
supportedBrowsers: [
|
|
||||||
"Chrome >= 52",
|
|
||||||
"Firefox >= 47",
|
|
||||||
"Safari >= 10",
|
|
||||||
"Edge == All",
|
|
||||||
"IE == 11"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
session: {
|
|
||||||
secret: "averysecretstring"
|
|
||||||
},
|
|
||||||
security: {
|
|
||||||
code: "0000" // <- Only 4 digits
|
|
||||||
},
|
|
||||||
unifi: {
|
|
||||||
ip: '192.168.1.XX',
|
|
||||||
port: 8443,
|
|
||||||
username: 'admin',
|
|
||||||
password: 'XXXXXXXXXXXXXXXXXXX',
|
|
||||||
siteID: 'default'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = config;
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
class BaseController {
|
|
||||||
constructor() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a response to express
|
|
||||||
*
|
|
||||||
* @param response
|
|
||||||
* @param status
|
|
||||||
* @param data
|
|
||||||
* @param contentType
|
|
||||||
*/
|
|
||||||
jsonResponse(response, status, data, contentType = 'application/json') {
|
|
||||||
response.type(contentType);
|
|
||||||
response.status(status);
|
|
||||||
response.json(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = BaseController;
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
const baseController = require('./BaseController');
|
|
||||||
|
|
||||||
class IndexController extends baseController {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action for the default api route
|
|
||||||
*
|
|
||||||
* @param req
|
|
||||||
* @param res
|
|
||||||
*/
|
|
||||||
indexAction(req, res) {
|
|
||||||
this.jsonResponse(res, 200, { 'message': 'Default API route!' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = new IndexController();
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
const config = require("../../config/config");
|
const config = require("../config/config");
|
||||||
const assets = require("../../helpers/modules/Assets");
|
const assets = require("../modules/Assets");
|
||||||
|
|
||||||
class BaseController {
|
class BaseController {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
const fs = require("fs");
|
|
||||||
const path = `${__dirname}/../../../public/dist`;
|
|
||||||
|
|
||||||
module.exports = () => {
|
|
||||||
return JSON.parse(fs.existsSync(path) ? fs.readFileSync(`${path}/rev-manifest.json`) : "{}");
|
|
||||||
};
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
class Router {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An easy to use function to add multiple routes to the Express router
|
|
||||||
*
|
|
||||||
* @param router
|
|
||||||
* @param routes
|
|
||||||
* @param type
|
|
||||||
*/
|
|
||||||
routesToRouter(router, routes, type) {
|
|
||||||
for (let item = 0; item < routes.length; item += 1) {
|
|
||||||
const route = routes[item];
|
|
||||||
const controller = route.controller.charAt(0).toUpperCase() + route.controller.slice(1);
|
|
||||||
eval(
|
|
||||||
`
|
|
||||||
const ${route.controller}Controller = require('../../controllers/${type}/${controller}Controller');
|
|
||||||
router.${route.method}('${route.route}', (req, res) => {
|
|
||||||
${route.controller}Controller.${route.action}Action(req, res);
|
|
||||||
});
|
|
||||||
`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = new Router();
|
|
||||||
18
app/modules/Assets.js
Normal file
18
app/modules/Assets.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* Import vendor modules
|
||||||
|
*/
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define public path
|
||||||
|
*/
|
||||||
|
const path = `${__dirname}/../../public/dist`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the manifest
|
||||||
|
*
|
||||||
|
* @return {any}
|
||||||
|
*/
|
||||||
|
module.exports = () => {
|
||||||
|
return JSON.parse(fs.existsSync(path) ? fs.readFileSync(`${path}/rev-manifest.json`) : "{}");
|
||||||
|
};
|
||||||
@@ -1,8 +1,23 @@
|
|||||||
const uuidv4 = require('uuid/v4');
|
/**
|
||||||
const config = require('../../config/config');
|
* Import vendor packages
|
||||||
|
*/
|
||||||
|
const { v4: uuidv4 } = require('uuid');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import own packages
|
||||||
|
*/
|
||||||
|
const config = require('../config/config');
|
||||||
const unifi = require('./UniFi');
|
const unifi = require('./UniFi');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Socket
|
||||||
|
*/
|
||||||
class Socket {
|
class Socket {
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param server
|
||||||
|
*/
|
||||||
constructor(server) {
|
constructor(server) {
|
||||||
this.io = require('socket.io')(server);
|
this.io = require('socket.io')(server);
|
||||||
this.authenticatedUsers = [];
|
this.authenticatedUsers = [];
|
||||||
@@ -125,4 +140,9 @@ class Socket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export the socket class
|
||||||
|
*
|
||||||
|
* @type {Socket}
|
||||||
|
*/
|
||||||
module.exports = Socket;
|
module.exports = Socket;
|
||||||
@@ -1,5 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* Import vendor modules
|
||||||
|
*/
|
||||||
const unifi = require('node-unifi');
|
const unifi = require('node-unifi');
|
||||||
const config = require('../../config/config');
|
|
||||||
|
/**
|
||||||
|
* Import own modules
|
||||||
|
*/
|
||||||
|
const config = require('../config/config');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new UniFi controller object
|
* Create new UniFi controller object
|
||||||
@@ -8,6 +15,11 @@ const config = require('../../config/config');
|
|||||||
*/
|
*/
|
||||||
const controller = new unifi.Controller(config.unifi.ip, config.unifi.port);
|
const controller = new unifi.Controller(config.unifi.ip, config.unifi.port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports the UniFi voucher function
|
||||||
|
*
|
||||||
|
* @param callback
|
||||||
|
*/
|
||||||
module.exports = (callback) => {
|
module.exports = (callback) => {
|
||||||
controller.login(config.unifi.username, config.unifi.password, (err) => {
|
controller.login(config.unifi.username, config.unifi.password, (err) => {
|
||||||
if(err) {
|
if(err) {
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
/**
|
|
||||||
* Import base packages
|
|
||||||
*/
|
|
||||||
const express = require('express');
|
|
||||||
const router = express.Router();
|
|
||||||
const routerUtils = require('../helpers/modules/Router');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define routes
|
|
||||||
*/
|
|
||||||
const routes = [
|
|
||||||
{
|
|
||||||
route: '/',
|
|
||||||
method: 'get',
|
|
||||||
controller: 'Index',
|
|
||||||
action: 'index'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
routerUtils.routesToRouter(router, routes, 'Api');
|
|
||||||
|
|
||||||
module.exports = {router, routes};
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
/**
|
|
||||||
* Import base packages
|
|
||||||
*/
|
|
||||||
const express = require('express');
|
|
||||||
const router = express.Router();
|
|
||||||
const routerUtils = require('../helpers/modules/Router');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define routes
|
|
||||||
*/
|
|
||||||
const routes = [
|
|
||||||
{
|
|
||||||
route: '/',
|
|
||||||
method: 'get',
|
|
||||||
controller: 'Index',
|
|
||||||
action: 'index'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
routerUtils.routesToRouter(router, routes, 'Web');
|
|
||||||
|
|
||||||
module.exports = {router, routes};
|
|
||||||
@@ -3,18 +3,13 @@
|
|||||||
*/
|
*/
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const app = express();
|
const app = express();
|
||||||
const bodyParser = require('body-parser');
|
|
||||||
const session = require('express-session');
|
|
||||||
const browsersupport = require('express-browsersupport');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Import own packages
|
* Import own packages
|
||||||
*/
|
*/
|
||||||
const config = require('./config/config');
|
const config = require('./config/config');
|
||||||
const socket = require('./helpers/modules/Socket');
|
const socket = require('./modules/Socket');
|
||||||
const webRouter = require('./routers/Web');
|
const IndexController = require('./controllers/IndexController');
|
||||||
const apiRouter = require('./routers/Api');
|
|
||||||
const indexController = require('./controllers/Web/IndexController');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set template engine
|
* Set template engine
|
||||||
@@ -33,64 +28,10 @@ app.enable('trust proxy');
|
|||||||
app.use(express.static(`${__dirname}/../public`));
|
app.use(express.static(`${__dirname}/../public`));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure app to use bodyParser()
|
* Configure routes
|
||||||
*/
|
*/
|
||||||
app.use(bodyParser.urlencoded({extended: true}));
|
app.get('/', (req, res) => {
|
||||||
app.use(bodyParser.json());
|
IndexController.indexAction(req, res);
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure sessions in app
|
|
||||||
*/
|
|
||||||
app.use(session({secret: config.session.secret, resave: true, saveUninitialized: true}));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure app to use Browser Support
|
|
||||||
*/
|
|
||||||
app.use(browsersupport({
|
|
||||||
redirectUrl: "/oldbrowser",
|
|
||||||
supportedBrowsers: config.application.supportedBrowsers
|
|
||||||
}));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure routers
|
|
||||||
*/
|
|
||||||
app.use('/', webRouter.router);
|
|
||||||
app.use('/api', apiRouter.router);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render sitemap.xml and robots.txt
|
|
||||||
*/
|
|
||||||
app.get('/sitemap.xml', (req, res) => {
|
|
||||||
indexController.siteMapAction(req, res, webRouter.routes);
|
|
||||||
});
|
|
||||||
app.get('/robots.txt', (req, res) => {
|
|
||||||
indexController.robotsAction(req, res);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render old browser page
|
|
||||||
*/
|
|
||||||
app.get('/oldbrowser', (req, res) => {
|
|
||||||
indexController.oldBrowserAction(req, res);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setup default 404 message
|
|
||||||
*/
|
|
||||||
app.use((req, res) => {
|
|
||||||
res.status(404);
|
|
||||||
|
|
||||||
// respond with json
|
|
||||||
if (req.originalUrl.split('/')[1] === 'api') {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* API 404 not found
|
|
||||||
*/
|
|
||||||
res.send({error: 'This API route is not implemented yet'});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
indexController.notFoundAction(req, res);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
<h2>404 Not Found !</h2>
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
<h2>Old Browser</h2>
|
|
||||||
<p>
|
|
||||||
Please update your browser to make sure our website works properly
|
|
||||||
</p>
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
User-agent: *
|
|
||||||
Disallow: /fonts/
|
|
||||||
Disallow: /scss/
|
|
||||||
Sitemap: <%= baseUrl %>sitemap.xml
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
|
||||||
<url>
|
|
||||||
<loc><%= baseUrl %></loc>
|
|
||||||
<changefreq>daily</changefreq>
|
|
||||||
<priority>1.0</priority>
|
|
||||||
</url>
|
|
||||||
<% routes.forEach((route) => { %>
|
|
||||||
<% if(route.route !== "/") { %>
|
|
||||||
<url>
|
|
||||||
<loc><%= baseUrl %><%= route.route.substring(1) %></loc>
|
|
||||||
<changefreq>monthly</changefreq>
|
|
||||||
<priority>0.5</priority>
|
|
||||||
</url>
|
|
||||||
<% } %>
|
|
||||||
<% }); %>
|
|
||||||
</urlset>
|
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<% include ./partials/head.ejs %>
|
<%- include('partials/head') %>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<% include ./partials/preloader.ejs %>
|
<%- include('partials/preloader') %>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<%- include(template) %>
|
<%- include(template) %>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<% include ./partials/footer.ejs %>
|
<%- include('partials/footer') %>
|
||||||
<script>
|
<script>
|
||||||
var expressConfig = {protocol: '<%= protocol %>', hostname: '<%= hostname %>', baseUrl: '<%= baseUrl %>'};
|
var expressConfig = {protocol: '<%= protocol %>', hostname: '<%= hostname %>', baseUrl: '<%= baseUrl %>'};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<div id="particles"></div>
|
<div id="particles"></div>
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<div id="center">
|
<div id="center">
|
||||||
<img src="/images/unifi-icon.png" alt="UniFi Icon" /><br/>
|
<img src="/images/unifi-icon.png" alt="UniFi Icon" width="100px" height="100px" /><br/>
|
||||||
<h2><%= config.application.name %></h2>
|
<h2><%= config.application.name %></h2>
|
||||||
|
|
||||||
<div id="sign-in">
|
<div id="sign-in">
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<footer>
|
<footer>
|
||||||
<p>© Copyright The Awesome People</p>
|
<p>UniFi Voucher | <a href="https://github.com/glenndehaan/unifi-voucher-site" rel="noreferrer noopener">GitHub</a></p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -3,14 +3,13 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimal-ui">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimal-ui">
|
||||||
|
|
||||||
<meta name="description" content="">
|
<meta name="description" content="UniFi Voucher">
|
||||||
<meta name="author" content="Glenn de Haan">
|
<meta name="author" content="Glenn de Haan">
|
||||||
<meta name="keywords" content="">
|
|
||||||
|
|
||||||
<meta property="og:title" content="<%= config.application.name %>"/>
|
<meta property="og:title" content="<%= config.application.name %>"/>
|
||||||
<meta property="og:type" content="website"/>
|
<meta property="og:type" content="website"/>
|
||||||
<meta property="og:url" content="<%= baseUrl %>"/>
|
<meta property="og:url" content="<%= baseUrl %>"/>
|
||||||
<meta property="og:description" content=""/>
|
<meta property="og:description" content="UniFi Voucher"/>
|
||||||
|
|
||||||
<link rel="alternate" href="<%= baseUrl %>" hreflang="en"/>
|
<link rel="alternate" href="<%= baseUrl %>" hreflang="en"/>
|
||||||
<link rel="canonical" href="<%= baseUrl %>"/>
|
<link rel="canonical" href="<%= baseUrl %>"/>
|
||||||
@@ -79,3 +78,4 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<link href="/dist/<%= assets.css %>" rel="stylesheet" type="text/css"/>
|
<link href="/dist/<%= assets.css %>" rel="stylesheet" type="text/css"/>
|
||||||
|
<link rel="preload" href="/fonts/text-security-disc.woff" as="font">
|
||||||
|
|||||||
13
docker-compose.yml
Normal file
13
docker-compose.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "8081:3001"
|
||||||
|
environment:
|
||||||
|
UNIFI_IP: '192.168.1.1'
|
||||||
|
UNIFI_PORT: 8443
|
||||||
|
UNIFI_USERNAME: 'admin'
|
||||||
|
UNIFI_PASSWORD: 'password'
|
||||||
|
UNIFI_SITE_ID: 'default'
|
||||||
|
SECURITY_CODE: '0000'
|
||||||
10966
package-lock.json
generated
10966
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
61
package.json
61
package.json
@@ -8,9 +8,9 @@
|
|||||||
"backend:start": "node ./app/server.js",
|
"backend:start": "node ./app/server.js",
|
||||||
"backend:dev": "nodemon -L --watch ./app ./app/server.js",
|
"backend:dev": "nodemon -L --watch ./app ./app/server.js",
|
||||||
"prebuild": "rimraf ./public/dist",
|
"prebuild": "rimraf ./public/dist",
|
||||||
"build": "cross-env NODE_ENV=production webpack --config ./_scripts/webpack.config.js --progress",
|
"build": "cross-env NODE_ENV=production webpack --mode production --config ./_scripts/webpack.config.js",
|
||||||
"prefrontend": "rimraf ./public/dist",
|
"prefrontend": "rimraf ./public/dist",
|
||||||
"frontend": "cross-env NODE_ENV=development webpack --config ./_scripts/webpack.config.js --watch --watch-poll -d --progress",
|
"frontend": "webpack --watch --mode development --config ./_scripts/webpack.config.js",
|
||||||
"lint": "eslint -c ./package.json ./app ./public/js"
|
"lint": "eslint -c ./package.json ./app ./public/js"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -38,9 +38,7 @@
|
|||||||
},
|
},
|
||||||
"globals": {
|
"globals": {
|
||||||
"site": false,
|
"site": false,
|
||||||
"expressConfig": false,
|
"expressConfig": false
|
||||||
"TimelineMax": false,
|
|
||||||
"TweenMax": false
|
|
||||||
},
|
},
|
||||||
"extends": [
|
"extends": [
|
||||||
"eslint:recommended"
|
"eslint:recommended"
|
||||||
@@ -49,36 +47,33 @@
|
|||||||
"author": "Glenn de Haan",
|
"author": "Glenn de Haan",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"autoprefixer": "^8.0.0",
|
"@babel/core": "^7.12.10",
|
||||||
"babel-core": "^6.26.0",
|
"@babel/preset-env": "^7.12.11",
|
||||||
"babel-loader": "^7.1.3",
|
"animejs": "^3.2.1",
|
||||||
"babel-preset-es2015": "^6.24.1",
|
"babel-core": "^6.26.3",
|
||||||
"body-parser": "^1.17.2",
|
"babel-loader": "^8.2.2",
|
||||||
"cross-env": "^5.1.3",
|
"cross-env": "^7.0.3",
|
||||||
"ejs": "^2.5.6",
|
"css-loader": "^5.0.1",
|
||||||
"express": "^4.15.3",
|
"ejs": "^3.1.5",
|
||||||
"express-browsersupport": "^1.3.3",
|
"express": "^4.17.1",
|
||||||
"express-session": "^1.15.6",
|
"gsap": "^3.6.0",
|
||||||
"extract-text-webpack-plugin": "^3.0.2",
|
"mini-css-extract-plugin": "^1.3.4",
|
||||||
"gsap": "^1.20.4",
|
"mitt": "^2.1.0",
|
||||||
"mitt": "^1.1.3",
|
"node-sass": "^5.0.0",
|
||||||
"node-sass": "^4.7.2",
|
"node-unifi": "^1.3.8",
|
||||||
"node-unifi": "^1.2.2",
|
|
||||||
"particles.js": "^2.0.0",
|
"particles.js": "^2.0.0",
|
||||||
"postcss": "^6.0.19",
|
"rimraf": "^3.0.2",
|
||||||
"postcss-loader": "^2.1.1",
|
"sass-loader": "^10.1.1",
|
||||||
"raw-loader": "^0.5.1",
|
"socket.io": "^3.1.0",
|
||||||
"rimraf": "^2.6.2",
|
"socket.io-client": "^3.1.0",
|
||||||
"sass-loader": "^6.0.6",
|
"uuid": "^8.3.2",
|
||||||
"socket.io": "^2.0.4",
|
"webpack": "^5.14.0",
|
||||||
"socket.io-client": "^2.0.4",
|
"webpack-cli": "^4.3.1",
|
||||||
"uuid": "^3.2.1",
|
"webpack-manifest-plugin": "^3.0.0"
|
||||||
"webpack": "^3.11.0",
|
|
||||||
"webpack-manifest-plugin": "^1.3.2"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"concurrently": "^3.5.1",
|
"concurrently": "^5.3.0",
|
||||||
"eslint": "^4.18.1",
|
"eslint": "^7.17.0",
|
||||||
"nodemon": "^1.15.1"
|
"nodemon": "^2.0.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import mitt from 'mitt';
|
import mitt from 'mitt';
|
||||||
import 'gsap/TweenMax';
|
|
||||||
import 'gsap/TimelineMax';
|
|
||||||
import settings from './settings';
|
import settings from './settings';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import io from 'socket.io-client';
|
import io from 'socket.io-client';
|
||||||
|
import animejs from 'animejs';
|
||||||
|
|
||||||
export default class Socket {
|
export default class Socket {
|
||||||
constructor({el}) {
|
constructor({el}) {
|
||||||
@@ -13,8 +14,6 @@ export default class Socket {
|
|||||||
this.errorContainer = document.querySelector("#error");
|
this.errorContainer = document.querySelector("#error");
|
||||||
this.preloader = document.querySelector("#preloader");
|
this.preloader = document.querySelector("#preloader");
|
||||||
|
|
||||||
this.tl = new TimelineMax();
|
|
||||||
|
|
||||||
document.querySelector("#voucher button").addEventListener("click", () => this.requestVoucher());
|
document.querySelector("#voucher button").addEventListener("click", () => this.requestVoucher());
|
||||||
|
|
||||||
this.init();
|
this.init();
|
||||||
@@ -46,12 +45,12 @@ export default class Socket {
|
|||||||
this.socket.emit('uuid');
|
this.socket.emit('uuid');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tl
|
animejs({
|
||||||
.to(this.mainContainer, 0.5, {
|
targets: this.mainContainer,
|
||||||
opacity: 0,
|
duration: 250,
|
||||||
display: "none"
|
opacity: [1, 0],
|
||||||
})
|
easing: 'linear',
|
||||||
.add(() => {
|
complete: () => {
|
||||||
if (!this.userSignedIn) {
|
if (!this.userSignedIn) {
|
||||||
this.signInContainer.classList.remove("hidden");
|
this.signInContainer.classList.remove("hidden");
|
||||||
} else {
|
} else {
|
||||||
@@ -59,11 +58,15 @@ export default class Socket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.errorContainer.classList.add("hidden");
|
this.errorContainer.classList.add("hidden");
|
||||||
})
|
|
||||||
.to(this.mainContainer, 0.5, {
|
animejs({
|
||||||
opacity: 1,
|
targets: this.mainContainer,
|
||||||
display: "block"
|
duration: 250,
|
||||||
});
|
opacity: [0, 1],
|
||||||
|
easing: 'linear',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,20 +75,24 @@ export default class Socket {
|
|||||||
disconnect() {
|
disconnect() {
|
||||||
console.log('[SOCKET] Disconnected!');
|
console.log('[SOCKET] Disconnected!');
|
||||||
|
|
||||||
this.tl
|
animejs({
|
||||||
.to(this.mainContainer, 0.5, {
|
targets: this.mainContainer,
|
||||||
opacity: 0,
|
duration: 250,
|
||||||
display: "none"
|
opacity: [1, 0],
|
||||||
})
|
easing: 'linear',
|
||||||
.add(() => {
|
complete: () => {
|
||||||
this.signInContainer.classList.add("hidden");
|
this.signInContainer.classList.add("hidden");
|
||||||
this.voucherContainer.classList.add("hidden");
|
this.voucherContainer.classList.add("hidden");
|
||||||
this.errorContainer.classList.remove("hidden");
|
this.errorContainer.classList.remove("hidden");
|
||||||
})
|
|
||||||
.to(this.mainContainer, 0.5, {
|
animejs({
|
||||||
opacity: 1,
|
targets: this.mainContainer,
|
||||||
display: "block"
|
duration: 250,
|
||||||
});
|
opacity: [0, 1],
|
||||||
|
easing: 'linear'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -94,20 +101,24 @@ export default class Socket {
|
|||||||
error() {
|
error() {
|
||||||
console.log('[SOCKET] Error!');
|
console.log('[SOCKET] Error!');
|
||||||
|
|
||||||
this.tl
|
animejs({
|
||||||
.to(this.mainContainer, 0.5, {
|
targets: this.mainContainer,
|
||||||
opacity: 0,
|
duration: 250,
|
||||||
display: "none"
|
opacity: [1, 0],
|
||||||
})
|
easing: 'linear',
|
||||||
.add(() => {
|
complete: () => {
|
||||||
this.signInContainer.classList.add("hidden");
|
this.signInContainer.classList.add("hidden");
|
||||||
this.voucherContainer.classList.add("hidden");
|
this.voucherContainer.classList.add("hidden");
|
||||||
this.errorContainer.classList.remove("hidden");
|
this.errorContainer.classList.remove("hidden");
|
||||||
})
|
|
||||||
.to(this.mainContainer, 0.5, {
|
animejs({
|
||||||
opacity: 1,
|
targets: this.mainContainer,
|
||||||
display: "block"
|
duration: 250,
|
||||||
});
|
opacity: [0, 1],
|
||||||
|
easing: 'linear'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,20 +135,24 @@ export default class Socket {
|
|||||||
if (data.success) {
|
if (data.success) {
|
||||||
this.userSignedIn = true;
|
this.userSignedIn = true;
|
||||||
|
|
||||||
this.tl
|
animejs({
|
||||||
.to(this.mainContainer, 0.5, {
|
targets: this.mainContainer,
|
||||||
opacity: 0,
|
duration: 250,
|
||||||
display: "none"
|
opacity: [1, 0],
|
||||||
})
|
easing: 'linear',
|
||||||
.add(() => {
|
complete: () => {
|
||||||
site.modules.Signin.resetForm();
|
site.modules.Signin.resetForm();
|
||||||
this.signInContainer.classList.add("hidden");
|
this.signInContainer.classList.add("hidden");
|
||||||
this.voucherContainer.classList.remove("hidden");
|
this.voucherContainer.classList.remove("hidden");
|
||||||
})
|
|
||||||
.to(this.mainContainer, 0.5, {
|
animejs({
|
||||||
opacity: 1,
|
targets: this.mainContainer,
|
||||||
display: "block"
|
duration: 250,
|
||||||
});
|
opacity: [0, 1],
|
||||||
|
easing: 'linear'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
site.modules.Signin.invalidCode();
|
site.modules.Signin.invalidCode();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
/**
|
|
||||||
* Function to post data to the API
|
|
||||||
*
|
|
||||||
* @param method
|
|
||||||
* @param data
|
|
||||||
* @param callback
|
|
||||||
* @param auth
|
|
||||||
*/
|
|
||||||
export default (method, data, callback, auth = "") => {
|
|
||||||
const xmlhttp = new XMLHttpRequest();
|
|
||||||
let route = "/api";
|
|
||||||
|
|
||||||
xmlhttp.open("POST", route);
|
|
||||||
xmlhttp.setRequestHeader("Content-Type", "application/json");
|
|
||||||
xmlhttp.setRequestHeader("Bearer", auth);
|
|
||||||
xmlhttp.send(JSON.stringify(data));
|
|
||||||
|
|
||||||
xmlhttp.onreadystatechange = function () {
|
|
||||||
if (xmlhttp.readyState === XMLHttpRequest.DONE) {
|
|
||||||
const responseCode = xmlhttp.status;
|
|
||||||
const response = JSON.parse(xmlhttp.responseText);
|
|
||||||
console.log('response', response);
|
|
||||||
|
|
||||||
console.log('responseCode', responseCode);
|
|
||||||
|
|
||||||
if (responseCode === 200) {
|
|
||||||
callback({error: false});
|
|
||||||
} else {
|
|
||||||
callback({error: true, fields: response.fields, raw_error: response.error});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user