stop
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
node_modules
|
||||||
41
server/app/pixel/app.js
Normal file
41
server/app/pixel/app.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
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 app = express();
|
||||||
|
|
||||||
|
// view engine setup
|
||||||
|
app.set('views', path.join(__dirname, 'views'));
|
||||||
|
app.set('view engine', 'jade');
|
||||||
|
|
||||||
|
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('/', indexRouter);
|
||||||
|
app.use('/users', usersRouter);
|
||||||
|
|
||||||
|
// catch 404 and forward to error handler
|
||||||
|
app.use(function(req, res, next) {
|
||||||
|
next(createError(404));
|
||||||
|
});
|
||||||
|
|
||||||
|
// error handler
|
||||||
|
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 : {};
|
||||||
|
|
||||||
|
// render the error page
|
||||||
|
res.status(err.status || 500);
|
||||||
|
res.render('error');
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = app;
|
||||||
90
server/app/pixel/bin/www
Executable file
90
server/app/pixel/bin/www
Executable file
@@ -0,0 +1,90 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var app = require('../app');
|
||||||
|
var debug = require('debug')('pixel:server');
|
||||||
|
var http = require('http');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get port from environment and store in Express.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var port = normalizePort(process.env.PORT || '3000');
|
||||||
|
app.set('port', port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create HTTP server.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var server = http.createServer(app);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen on provided port, on all network interfaces.
|
||||||
|
*/
|
||||||
|
|
||||||
|
server.listen(port);
|
||||||
|
server.on('error', onError);
|
||||||
|
server.on('listening', onListening);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize a port into a number, string, or false.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function normalizePort(val) {
|
||||||
|
var port = parseInt(val, 10);
|
||||||
|
|
||||||
|
if (isNaN(port)) {
|
||||||
|
// named pipe
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port >= 0) {
|
||||||
|
// port number
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event listener for HTTP server "error" event.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onError(error) {
|
||||||
|
if (error.syscall !== 'listen') {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
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');
|
||||||
|
process.exit(1);
|
||||||
|
break;
|
||||||
|
case 'EADDRINUSE':
|
||||||
|
console.error(bind + ' is already in use');
|
||||||
|
process.exit(1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event listener for HTTP server "listening" event.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onListening() {
|
||||||
|
var addr = server.address();
|
||||||
|
var bind = typeof addr === 'string'
|
||||||
|
? 'pipe ' + addr
|
||||||
|
: 'port ' + addr.port;
|
||||||
|
debug('Listening on ' + bind);
|
||||||
|
}
|
||||||
16
server/app/pixel/package.json
Normal file
16
server/app/pixel/package.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "pixel",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"start": "node ./bin/www"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"cookie-parser": "~1.4.4",
|
||||||
|
"debug": "~2.6.9",
|
||||||
|
"express": "~4.16.1",
|
||||||
|
"http-errors": "~1.6.3",
|
||||||
|
"jade": "~1.11.0",
|
||||||
|
"morgan": "~1.9.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
8
server/app/pixel/public/stylesheets/style.css
Normal file
8
server/app/pixel/public/stylesheets/style.css
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
body {
|
||||||
|
padding: 50px;
|
||||||
|
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #00B7FF;
|
||||||
|
}
|
||||||
9
server/app/pixel/routes/index.js
Normal file
9
server/app/pixel/routes/index.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
var express = require('express');
|
||||||
|
var router = express.Router();
|
||||||
|
|
||||||
|
/* GET home page. */
|
||||||
|
router.get('/', function(req, res, next) {
|
||||||
|
res.render('index', { title: 'Express' });
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
9
server/app/pixel/routes/users.js
Normal file
9
server/app/pixel/routes/users.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
var express = require('express');
|
||||||
|
var router = express.Router();
|
||||||
|
|
||||||
|
/* GET users listing. */
|
||||||
|
router.get('/', function(req, res, next) {
|
||||||
|
res.send('respond with a resource');
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
6
server/app/pixel/views/error.jade
Normal file
6
server/app/pixel/views/error.jade
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
extends layout
|
||||||
|
|
||||||
|
block content
|
||||||
|
h1= message
|
||||||
|
h2= error.status
|
||||||
|
pre #{error.stack}
|
||||||
5
server/app/pixel/views/index.jade
Normal file
5
server/app/pixel/views/index.jade
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
extends layout
|
||||||
|
|
||||||
|
block content
|
||||||
|
h1= title
|
||||||
|
p Welcome to #{title}
|
||||||
7
server/app/pixel/views/layout.jade
Normal file
7
server/app/pixel/views/layout.jade
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
doctype html
|
||||||
|
html
|
||||||
|
head
|
||||||
|
title= title
|
||||||
|
link(rel='stylesheet', href='/stylesheets/style.css')
|
||||||
|
body
|
||||||
|
block content
|
||||||
13
server/app/worker-cli/index.ts
Normal file
13
server/app/worker-cli/index.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { IWorkerMessage } from "domain-worker/IWorkerMessage";
|
||||||
|
|
||||||
|
const worker: IWorkerMessage<any> = {
|
||||||
|
name: "yo",
|
||||||
|
payload: {
|
||||||
|
type: "message",
|
||||||
|
value: {
|
||||||
|
data: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(worker);
|
||||||
14
server/app/worker-cli/package.json
Normal file
14
server/app/worker-cli/package.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "worker-cli",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"start": "ts-node index.ts"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"domain-worker": "1.0.0",
|
||||||
|
"ts-node": "^9.1.1",
|
||||||
|
"typescript": "^4.2.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
63
server/app/worker-cli/yarn.lock
Normal file
63
server/app/worker-cli/yarn.lock
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
arg@^4.1.0:
|
||||||
|
version "4.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
|
||||||
|
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
|
||||||
|
|
||||||
|
buffer-from@^1.0.0:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
||||||
|
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
|
||||||
|
|
||||||
|
create-require@^1.1.0:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
||||||
|
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
||||||
|
|
||||||
|
diff@^4.0.1:
|
||||||
|
version "4.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
|
||||||
|
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
|
||||||
|
|
||||||
|
make-error@^1.1.1:
|
||||||
|
version "1.3.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
|
||||||
|
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
|
||||||
|
|
||||||
|
source-map-support@^0.5.17:
|
||||||
|
version "0.5.19"
|
||||||
|
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
|
||||||
|
integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
|
||||||
|
dependencies:
|
||||||
|
buffer-from "^1.0.0"
|
||||||
|
source-map "^0.6.0"
|
||||||
|
|
||||||
|
source-map@^0.6.0:
|
||||||
|
version "0.6.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||||
|
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||||
|
|
||||||
|
ts-node@^9.1.1:
|
||||||
|
version "9.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d"
|
||||||
|
integrity sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==
|
||||||
|
dependencies:
|
||||||
|
arg "^4.1.0"
|
||||||
|
create-require "^1.1.0"
|
||||||
|
diff "^4.0.1"
|
||||||
|
make-error "^1.1.1"
|
||||||
|
source-map-support "^0.5.17"
|
||||||
|
yn "3.1.1"
|
||||||
|
|
||||||
|
typescript@^4.2.3:
|
||||||
|
version "4.2.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3"
|
||||||
|
integrity sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==
|
||||||
|
|
||||||
|
yn@3.1.1:
|
||||||
|
version "3.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
||||||
|
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
|
||||||
63
server/app/worker/build.ts
Normal file
63
server/app/worker/build.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* Remove old files, copy front-end ones.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
import Logger from 'jet-logger';
|
||||||
|
import childProcess from 'child_process';
|
||||||
|
|
||||||
|
// Setup logger
|
||||||
|
const logger = new Logger();
|
||||||
|
logger.timestamp = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
// Remove current build
|
||||||
|
await remove('./dist/');
|
||||||
|
// Copy front-end files
|
||||||
|
await copy('./src/public', './dist/public');
|
||||||
|
await copy('./src/views', './dist/views');
|
||||||
|
// Copy production env file
|
||||||
|
await copy('./src/pre-start/env/production.env', './dist/pre-start/env/production.env');
|
||||||
|
// Copy back-end files
|
||||||
|
await exec('tsc --build tsconfig.prod.json', './')
|
||||||
|
} catch (err) {
|
||||||
|
logger.err(err);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
function remove(loc: string): Promise<void> {
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
return fs.remove(loc, (err) => {
|
||||||
|
return (!!err ? rej(err) : res());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function copy(src: string, dest: string): Promise<void> {
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
return fs.copy(src, dest, (err) => {
|
||||||
|
return (!!err ? rej(err) : res());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function exec(cmd: string, loc: string): Promise<void> {
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
return childProcess.exec(cmd, {cwd: loc}, (err, stdout, stderr) => {
|
||||||
|
if (!!stdout) {
|
||||||
|
logger.info(stdout);
|
||||||
|
}
|
||||||
|
if (!!stderr) {
|
||||||
|
logger.warn(stderr);
|
||||||
|
}
|
||||||
|
return (!!err ? rej(err) : res());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
52
server/app/worker/dist/Server.js
vendored
Normal file
52
server/app/worker/dist/Server.js
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const cookie_parser_1 = __importDefault(require("cookie-parser"));
|
||||||
|
const morgan_1 = __importDefault(require("morgan"));
|
||||||
|
const path_1 = __importDefault(require("path"));
|
||||||
|
const helmet_1 = __importDefault(require("helmet"));
|
||||||
|
const express_1 = __importDefault(require("express"));
|
||||||
|
const http_status_codes_1 = __importDefault(require("http-status-codes"));
|
||||||
|
require("express-async-errors");
|
||||||
|
const routes_1 = __importDefault(require("./routes"));
|
||||||
|
const Logger_1 = __importDefault(require("@shared/Logger"));
|
||||||
|
const app = express_1.default();
|
||||||
|
const { BAD_REQUEST } = http_status_codes_1.default;
|
||||||
|
/************************************************************************************
|
||||||
|
* Set basic express settings
|
||||||
|
***********************************************************************************/
|
||||||
|
app.use(express_1.default.json());
|
||||||
|
app.use(express_1.default.urlencoded({ extended: true }));
|
||||||
|
app.use(cookie_parser_1.default());
|
||||||
|
// Show routes called in console during development
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
app.use(morgan_1.default('dev'));
|
||||||
|
}
|
||||||
|
// Security
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
app.use(helmet_1.default());
|
||||||
|
}
|
||||||
|
// Add APIs
|
||||||
|
app.use('/api', routes_1.default);
|
||||||
|
// Print API errors
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
app.use((err, req, res, next) => {
|
||||||
|
Logger_1.default.err(err, true);
|
||||||
|
return res.status(BAD_REQUEST).json({
|
||||||
|
error: err.message,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
/************************************************************************************
|
||||||
|
* Serve front-end content
|
||||||
|
***********************************************************************************/
|
||||||
|
const viewsDir = path_1.default.join(__dirname, 'views');
|
||||||
|
app.set('views', viewsDir);
|
||||||
|
const staticDir = path_1.default.join(__dirname, 'public');
|
||||||
|
app.use(express_1.default.static(staticDir));
|
||||||
|
app.get('*', (req, res) => {
|
||||||
|
res.sendFile('index.html', { root: viewsDir });
|
||||||
|
});
|
||||||
|
// Export express instance
|
||||||
|
exports.default = app;
|
||||||
18
server/app/worker/dist/daos/MockDb/MockDao.mock.js
vendored
Normal file
18
server/app/worker/dist/daos/MockDb/MockDao.mock.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const jsonfile_1 = __importDefault(require("jsonfile"));
|
||||||
|
class MockDaoMock {
|
||||||
|
constructor() {
|
||||||
|
this.dbFilePath = 'src/daos/MockDb/MockDb.json';
|
||||||
|
}
|
||||||
|
openDb() {
|
||||||
|
return jsonfile_1.default.readFile(this.dbFilePath);
|
||||||
|
}
|
||||||
|
saveDb(db) {
|
||||||
|
return jsonfile_1.default.writeFile(this.dbFilePath, db);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.default = MockDaoMock;
|
||||||
58
server/app/worker/dist/daos/User/UserDao.js
vendored
Normal file
58
server/app/worker/dist/daos/User/UserDao.js
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
"use strict";
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
class UserDao {
|
||||||
|
/**
|
||||||
|
* @param email
|
||||||
|
*/
|
||||||
|
getOne(email) {
|
||||||
|
// TODO
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
getAll() {
|
||||||
|
// TODO
|
||||||
|
return Promise.resolve([]);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
*/
|
||||||
|
add(user) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
// TODO
|
||||||
|
return Promise.resolve(undefined);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
*/
|
||||||
|
update(user) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
// TODO
|
||||||
|
return Promise.resolve(undefined);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
delete(id) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
// TODO
|
||||||
|
return Promise.resolve(undefined);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.default = UserDao;
|
||||||
88
server/app/worker/dist/daos/User/UserDao.mock.js
vendored
Normal file
88
server/app/worker/dist/daos/User/UserDao.mock.js
vendored
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
"use strict";
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const functions_1 = require("@shared/functions");
|
||||||
|
const MockDao_mock_1 = __importDefault(require("../MockDb/MockDao.mock"));
|
||||||
|
class UserDao extends MockDao_mock_1.default {
|
||||||
|
getOne(email) {
|
||||||
|
const _super = Object.create(null, {
|
||||||
|
openDb: { get: () => super.openDb }
|
||||||
|
});
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const db = yield _super.openDb.call(this);
|
||||||
|
for (const user of db.users) {
|
||||||
|
if (user.email === email) {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
getAll() {
|
||||||
|
const _super = Object.create(null, {
|
||||||
|
openDb: { get: () => super.openDb }
|
||||||
|
});
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const db = yield _super.openDb.call(this);
|
||||||
|
return db.users;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
add(user) {
|
||||||
|
const _super = Object.create(null, {
|
||||||
|
openDb: { get: () => super.openDb },
|
||||||
|
saveDb: { get: () => super.saveDb }
|
||||||
|
});
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const db = yield _super.openDb.call(this);
|
||||||
|
user.id = functions_1.getRandomInt();
|
||||||
|
db.users.push(user);
|
||||||
|
yield _super.saveDb.call(this, db);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
update(user) {
|
||||||
|
const _super = Object.create(null, {
|
||||||
|
openDb: { get: () => super.openDb },
|
||||||
|
saveDb: { get: () => super.saveDb }
|
||||||
|
});
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const db = yield _super.openDb.call(this);
|
||||||
|
for (let i = 0; i < db.users.length; i++) {
|
||||||
|
if (db.users[i].id === user.id) {
|
||||||
|
db.users[i] = user;
|
||||||
|
yield _super.saveDb.call(this, db);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error('User not found');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
delete(id) {
|
||||||
|
const _super = Object.create(null, {
|
||||||
|
openDb: { get: () => super.openDb },
|
||||||
|
saveDb: { get: () => super.saveDb }
|
||||||
|
});
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const db = yield _super.openDb.call(this);
|
||||||
|
for (let i = 0; i < db.users.length; i++) {
|
||||||
|
if (db.users[i].id === id) {
|
||||||
|
db.users.splice(i, 1);
|
||||||
|
yield _super.saveDb.call(this, db);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error('User not found');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.default = UserDao;
|
||||||
17
server/app/worker/dist/entities/User.js
vendored
Normal file
17
server/app/worker/dist/entities/User.js
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
class User {
|
||||||
|
constructor(nameOrUser, email, id) {
|
||||||
|
if (typeof nameOrUser === 'string') {
|
||||||
|
this.name = nameOrUser;
|
||||||
|
this.email = email || '';
|
||||||
|
this.id = id || -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.name = nameOrUser.name;
|
||||||
|
this.email = nameOrUser.email;
|
||||||
|
this.id = nameOrUser.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.default = User;
|
||||||
13
server/app/worker/dist/index.js
vendored
Normal file
13
server/app/worker/dist/index.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
require("./pre-start"); // Must be the first import
|
||||||
|
const _server_1 = __importDefault(require("@server"));
|
||||||
|
const Logger_1 = __importDefault(require("@shared/Logger"));
|
||||||
|
// Start the server
|
||||||
|
const port = Number(process.env.PORT || 3000);
|
||||||
|
_server_1.default.listen(port, () => {
|
||||||
|
Logger_1.default.info('Express server started on port: ' + port);
|
||||||
|
});
|
||||||
14
server/app/worker/dist/pre-start/env/production.env
vendored
Normal file
14
server/app/worker/dist/pre-start/env/production.env
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
## Environment ##
|
||||||
|
NODE_ENV=production
|
||||||
|
|
||||||
|
|
||||||
|
## Server ##
|
||||||
|
PORT=8081
|
||||||
|
HOST=localhost
|
||||||
|
|
||||||
|
|
||||||
|
## Setup jet-logger ##
|
||||||
|
JET_LOGGER_MODE=FILE
|
||||||
|
JET_LOGGER_FILEPATH=jet-logger.log
|
||||||
|
JET_LOGGER_TIMESTAMP=TRUE
|
||||||
|
JET_LOGGER_FORMAT=LINE
|
||||||
30
server/app/worker/dist/pre-start/index.js
vendored
Normal file
30
server/app/worker/dist/pre-start/index.js
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
"use strict";
|
||||||
|
/**
|
||||||
|
* Pre-start is where we want to place things that must run BEFORE the express server is started.
|
||||||
|
* This is useful for environment variables, command-line arguments, and cron-jobs.
|
||||||
|
*/
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const path_1 = __importDefault(require("path"));
|
||||||
|
const dotenv_1 = __importDefault(require("dotenv"));
|
||||||
|
const command_line_args_1 = __importDefault(require("command-line-args"));
|
||||||
|
(() => {
|
||||||
|
// Setup command line options
|
||||||
|
const options = command_line_args_1.default([
|
||||||
|
{
|
||||||
|
name: 'env',
|
||||||
|
alias: 'e',
|
||||||
|
defaultValue: 'development',
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
// Set the env file
|
||||||
|
const result2 = dotenv_1.default.config({
|
||||||
|
path: path_1.default.join(__dirname, `env/${options.env}.env`),
|
||||||
|
});
|
||||||
|
if (result2.error) {
|
||||||
|
throw result2.error;
|
||||||
|
}
|
||||||
|
})();
|
||||||
171
server/app/worker/dist/public/scripts/index.js
vendored
Normal file
171
server/app/worker/dist/public/scripts/index.js
vendored
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Fetch and display users
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
displayUsers();
|
||||||
|
|
||||||
|
|
||||||
|
function displayUsers() {
|
||||||
|
httpGet('/api/users/all')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then((response) => {
|
||||||
|
var allUsers = response.users;
|
||||||
|
// Empty the anchor
|
||||||
|
var allUsersAnchor = document.getElementById('all-users-anchor');
|
||||||
|
allUsersAnchor.innerHTML = '';
|
||||||
|
// Append users to anchor
|
||||||
|
allUsers.forEach((user) => {
|
||||||
|
allUsersAnchor.innerHTML += getUserDisplayEle(user);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function getUserDisplayEle(user) {
|
||||||
|
return `<div class="user-display-ele">
|
||||||
|
|
||||||
|
<div class="normal-view">
|
||||||
|
<div>Name: ${user.name}</div>
|
||||||
|
<div>Email: ${user.email}</div>
|
||||||
|
<button class="edit-user-btn" data-user-id="${user.id}">
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
<button class="delete-user-btn" data-user-id="${user.id}">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="edit-view">
|
||||||
|
<div>
|
||||||
|
Name: <input class="name-edit-input" value="${user.name}">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Email: <input class="email-edit-input" value="${user.email}">
|
||||||
|
</div>
|
||||||
|
<button class="submit-edit-btn" data-user-id="${user.id}">
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
<button class="cancel-edit-btn" data-user-id="${user.id}">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Add, Edit, and Delete Users
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
document.addEventListener('click', function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
var ele = event.target;
|
||||||
|
if (ele.matches('#add-user-btn')) {
|
||||||
|
addUser();
|
||||||
|
} else if (ele.matches('.edit-user-btn')) {
|
||||||
|
showEditView(ele.parentNode.parentNode);
|
||||||
|
} else if (ele.matches('.cancel-edit-btn')) {
|
||||||
|
cancelEdit(ele.parentNode.parentNode);
|
||||||
|
} else if (ele.matches('.submit-edit-btn')) {
|
||||||
|
submitEdit(ele);
|
||||||
|
} else if (ele.matches('.delete-user-btn')) {
|
||||||
|
deleteUser(ele);
|
||||||
|
}
|
||||||
|
}, false)
|
||||||
|
|
||||||
|
|
||||||
|
function addUser() {
|
||||||
|
var nameInput = document.getElementById('name-input');
|
||||||
|
var emailInput = document.getElementById('email-input');
|
||||||
|
var data = {
|
||||||
|
user: {
|
||||||
|
name: nameInput.value,
|
||||||
|
email: emailInput.value
|
||||||
|
},
|
||||||
|
};
|
||||||
|
httpPost('/api/users/add', data)
|
||||||
|
.then(() => {
|
||||||
|
displayUsers();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function showEditView(userEle) {
|
||||||
|
var normalView = userEle.getElementsByClassName('normal-view')[0];
|
||||||
|
var editView = userEle.getElementsByClassName('edit-view')[0];
|
||||||
|
normalView.style.display = 'none';
|
||||||
|
editView.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function cancelEdit(userEle) {
|
||||||
|
var normalView = userEle.getElementsByClassName('normal-view')[0];
|
||||||
|
var editView = userEle.getElementsByClassName('edit-view')[0];
|
||||||
|
normalView.style.display = 'block';
|
||||||
|
editView.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function submitEdit(ele) {
|
||||||
|
var userEle = ele.parentNode.parentNode;
|
||||||
|
var nameInput = userEle.getElementsByClassName('name-edit-input')[0];
|
||||||
|
var emailInput = userEle.getElementsByClassName('email-edit-input')[0];
|
||||||
|
var id = ele.getAttribute('data-user-id');
|
||||||
|
var data = {
|
||||||
|
user: {
|
||||||
|
name: nameInput.value,
|
||||||
|
email: emailInput.value,
|
||||||
|
id: id
|
||||||
|
}
|
||||||
|
};
|
||||||
|
httpPut('/api/users/update', data)
|
||||||
|
.then(() => {
|
||||||
|
displayUsers();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function deleteUser(ele) {
|
||||||
|
var id = ele.getAttribute('data-user-id');
|
||||||
|
httpDelete('/api/users/delete/' + id)
|
||||||
|
.then(() => {
|
||||||
|
displayUsers();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function httpGet(path) {
|
||||||
|
return fetch(path, getOptions('GET'))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function httpPost(path, data) {
|
||||||
|
return fetch(path, getOptions('POST', data));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function httpPut(path, data) {
|
||||||
|
return fetch(path, getOptions('PUT', data));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function httpDelete(path) {
|
||||||
|
return fetch(path, getOptions('DELETE'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getOptions(verb, data) {
|
||||||
|
var options = {
|
||||||
|
dataType: 'json',
|
||||||
|
method: verb,
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (data) {
|
||||||
|
options.body = JSON.stringify(data);
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
33
server/app/worker/dist/public/stylesheets/style.css
vendored
Normal file
33
server/app/worker/dist/public/stylesheets/style.css
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
body {
|
||||||
|
padding: 100px;
|
||||||
|
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .users-column {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 2em;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .users-column .column-header {
|
||||||
|
padding-bottom: 5px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .add-user-col input {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .users-column .user-display-ele {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .users-column .user-display-ele button {
|
||||||
|
margin-top: 2px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .users-column .user-display-ele .edit-view {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
67
server/app/worker/dist/routes/Users.js
vendored
Normal file
67
server/app/worker/dist/routes/Users.js
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
"use strict";
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const http_status_codes_1 = __importDefault(require("http-status-codes"));
|
||||||
|
const express_1 = require("express");
|
||||||
|
const UserDao_mock_1 = __importDefault(require("@daos/User/UserDao.mock"));
|
||||||
|
const constants_1 = require("@shared/constants");
|
||||||
|
const router = express_1.Router();
|
||||||
|
const userDao = new UserDao_mock_1.default();
|
||||||
|
const { BAD_REQUEST, CREATED, OK } = http_status_codes_1.default;
|
||||||
|
/******************************************************************************
|
||||||
|
* Get All Users - "GET /api/users/all"
|
||||||
|
******************************************************************************/
|
||||||
|
router.get('/all', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
const users = yield userDao.getAll();
|
||||||
|
return res.status(OK).json({ users });
|
||||||
|
}));
|
||||||
|
/******************************************************************************
|
||||||
|
* Add One - "POST /api/users/add"
|
||||||
|
******************************************************************************/
|
||||||
|
router.post('/add', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
const { user } = req.body;
|
||||||
|
if (!user) {
|
||||||
|
return res.status(BAD_REQUEST).json({
|
||||||
|
error: constants_1.paramMissingError,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
yield userDao.add(user);
|
||||||
|
return res.status(CREATED).end();
|
||||||
|
}));
|
||||||
|
/******************************************************************************
|
||||||
|
* Update - "PUT /api/users/update"
|
||||||
|
******************************************************************************/
|
||||||
|
router.put('/update', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
const { user } = req.body;
|
||||||
|
if (!user) {
|
||||||
|
return res.status(BAD_REQUEST).json({
|
||||||
|
error: constants_1.paramMissingError,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
user.id = Number(user.id);
|
||||||
|
yield userDao.update(user);
|
||||||
|
return res.status(OK).end();
|
||||||
|
}));
|
||||||
|
/******************************************************************************
|
||||||
|
* Delete - "DELETE /api/users/delete/:id"
|
||||||
|
******************************************************************************/
|
||||||
|
router.delete('/delete/:id', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
const { id } = req.params;
|
||||||
|
yield userDao.delete(Number(id));
|
||||||
|
return res.status(OK).end();
|
||||||
|
}));
|
||||||
|
/******************************************************************************
|
||||||
|
* Export
|
||||||
|
******************************************************************************/
|
||||||
|
exports.default = router;
|
||||||
13
server/app/worker/dist/routes/index.js
vendored
Normal file
13
server/app/worker/dist/routes/index.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const express_1 = require("express");
|
||||||
|
const Users_1 = __importDefault(require("./Users"));
|
||||||
|
// Init router and path
|
||||||
|
const router = express_1.Router();
|
||||||
|
// Add sub-routes
|
||||||
|
router.use('/users', Users_1.default);
|
||||||
|
// Export the base-router
|
||||||
|
exports.default = router;
|
||||||
13
server/app/worker/dist/shared/Logger.js
vendored
Normal file
13
server/app/worker/dist/shared/Logger.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
"use strict";
|
||||||
|
/**
|
||||||
|
* Setup the jet-logger.
|
||||||
|
*
|
||||||
|
* Documentation: https://github.com/seanpmaxwell/jet-logger
|
||||||
|
*/
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const jet_logger_1 = __importDefault(require("jet-logger"));
|
||||||
|
const logger = new jet_logger_1.default();
|
||||||
|
exports.default = logger;
|
||||||
4
server/app/worker/dist/shared/constants.js
vendored
Normal file
4
server/app/worker/dist/shared/constants.js
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.paramMissingError = void 0;
|
||||||
|
exports.paramMissingError = 'One or more of the required parameters was missing.';
|
||||||
17
server/app/worker/dist/shared/functions.js
vendored
Normal file
17
server/app/worker/dist/shared/functions.js
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.getRandomInt = exports.pErr = void 0;
|
||||||
|
const Logger_1 = __importDefault(require("./Logger"));
|
||||||
|
const pErr = (err) => {
|
||||||
|
if (err) {
|
||||||
|
Logger_1.default.err(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.pErr = pErr;
|
||||||
|
const getRandomInt = () => {
|
||||||
|
return Math.floor(Math.random() * 1000000000000);
|
||||||
|
};
|
||||||
|
exports.getRandomInt = getRandomInt;
|
||||||
34
server/app/worker/dist/views/index.html
vendored
Normal file
34
server/app/worker/dist/views/index.html
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>ExpressGeneratorTypeScriptApp</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/stylesheets/style.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<!-- Add Users -->
|
||||||
|
<div class="users-column add-user-col">
|
||||||
|
<div class="column-header">Add User:</div>
|
||||||
|
<div>
|
||||||
|
<input id="name-input" placeholder="Name">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input id="email-input" placeholder="Email">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button id="add-user-btn">Add</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Display Users -->
|
||||||
|
<div class="users-column">
|
||||||
|
<div class="column-header">Users:</div>
|
||||||
|
<div id="all-users-anchor"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
<script src="scripts/index.js"></script>
|
||||||
|
</html>
|
||||||
98
server/app/worker/package.json
Normal file
98
server/app/worker/package.json
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
{
|
||||||
|
"name": "worker",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"build": "./node_modules/.bin/ts-node build.ts",
|
||||||
|
"lint": "eslint . --ext .ts",
|
||||||
|
"start": "node -r module-alias/register ./dist --env=production",
|
||||||
|
"start:dev": "nodemon",
|
||||||
|
"test": "nodemon --config ./spec/nodemon.json"
|
||||||
|
},
|
||||||
|
"nodemonConfig": {
|
||||||
|
"watch": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"ext": "ts, html",
|
||||||
|
"ignore": [
|
||||||
|
"src/public"
|
||||||
|
],
|
||||||
|
"exec": "./node_modules/.bin/ts-node -r tsconfig-paths/register ./src"
|
||||||
|
},
|
||||||
|
"_moduleAliases": {
|
||||||
|
"@daos": "dist/daos",
|
||||||
|
"@entities": "dist/entities",
|
||||||
|
"@shared": "dist/shared",
|
||||||
|
"@server": "dist/Server"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"plugins": [
|
||||||
|
"@typescript-eslint"
|
||||||
|
],
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended-requiring-type-checking"
|
||||||
|
],
|
||||||
|
"parserOptions": {
|
||||||
|
"project": "./tsconfig.json"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"max-len": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"code": 100
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"no-console": 1,
|
||||||
|
"no-extra-boolean-cast": 0,
|
||||||
|
"@typescript-eslint/restrict-plus-operands": 0,
|
||||||
|
"@typescript-eslint/explicit-module-boundary-types": 0,
|
||||||
|
"@typescript-eslint/no-explicit-any": 0,
|
||||||
|
"@typescript-eslint/no-floating-promises": 0,
|
||||||
|
"@typescript-eslint/no-unsafe-member-access": 0,
|
||||||
|
"@typescript-eslint/no-unsafe-assignment": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"eslintIgnore": [
|
||||||
|
"src/public/",
|
||||||
|
"build.ts"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"command-line-args": "^5.1.1",
|
||||||
|
"cookie-parser": "^1.4.5",
|
||||||
|
"domain-worker": "1.0.0",
|
||||||
|
"dotenv": "^8.2.0",
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"express-async-errors": "^3.1.1",
|
||||||
|
"helmet": "^4.4.1",
|
||||||
|
"http-status-codes": "^2.1.4",
|
||||||
|
"jet-logger": "^1.0.4",
|
||||||
|
"jsonfile": "^6.1.0",
|
||||||
|
"module-alias": "^2.2.2",
|
||||||
|
"morgan": "^1.10.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/command-line-args": "^5.0.0",
|
||||||
|
"@types/cookie-parser": "^1.4.2",
|
||||||
|
"@types/express": "^4.17.11",
|
||||||
|
"@types/find": "^0.2.1",
|
||||||
|
"@types/fs-extra": "^9.0.8",
|
||||||
|
"@types/jasmine": "^3.6.7",
|
||||||
|
"@types/jsonfile": "^6.0.0",
|
||||||
|
"@types/morgan": "^1.9.2",
|
||||||
|
"@types/node": "^14.14.35",
|
||||||
|
"@types/supertest": "^2.0.10",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^4.19.0",
|
||||||
|
"@typescript-eslint/parser": "^4.19.0",
|
||||||
|
"eslint": "^7.22.0",
|
||||||
|
"find": "^0.3.0",
|
||||||
|
"fs-extra": "^9.1.0",
|
||||||
|
"jasmine": "^3.7.0",
|
||||||
|
"nodemon": "^2.0.7",
|
||||||
|
"supertest": "^6.1.3",
|
||||||
|
"ts-node": "^9.1.1",
|
||||||
|
"tsconfig-paths": "^3.9.0",
|
||||||
|
"typescript": "^4.2.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
54
server/app/worker/spec/index.ts
Normal file
54
server/app/worker/spec/index.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import './loadEnv';
|
||||||
|
import find from 'find';
|
||||||
|
import Jasmine from 'jasmine';
|
||||||
|
import commandLineArgs from 'command-line-args';
|
||||||
|
import logger from '@shared/Logger';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Setup command line options
|
||||||
|
const options = commandLineArgs([
|
||||||
|
{
|
||||||
|
name: 'testFile',
|
||||||
|
alias: 'f',
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
// Init Jasmine
|
||||||
|
const jasmine = new Jasmine(null);
|
||||||
|
|
||||||
|
// Set location of test files
|
||||||
|
jasmine.loadConfig({
|
||||||
|
random: true,
|
||||||
|
spec_dir: 'spec',
|
||||||
|
spec_files: [
|
||||||
|
'./tests/**/*.spec.ts',
|
||||||
|
],
|
||||||
|
stopSpecOnExpectationFailure: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// On complete callback function
|
||||||
|
jasmine.onComplete((passed: boolean) => {
|
||||||
|
if (passed) {
|
||||||
|
logger.info('All tests have passed :)');
|
||||||
|
} else {
|
||||||
|
logger.err('At least one test has failed :(');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Run all or a single unit-test
|
||||||
|
if (options.testFile) {
|
||||||
|
const testFile = options.testFile as string;
|
||||||
|
find.file(testFile + '.spec.ts', './spec', (files) => {
|
||||||
|
if (files.length === 1) {
|
||||||
|
jasmine.specFiles = [files[0]];
|
||||||
|
jasmine.execute();
|
||||||
|
} else {
|
||||||
|
logger.err('Test file not found!');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
jasmine.execute();
|
||||||
|
}
|
||||||
10
server/app/worker/spec/loadEnv.ts
Normal file
10
server/app/worker/spec/loadEnv.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// Set the env file, must be first
|
||||||
|
import dotenv from 'dotenv';
|
||||||
|
|
||||||
|
const result2 = dotenv.config({
|
||||||
|
path: `./src/pre-start/env/test.env`,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result2.error) {
|
||||||
|
throw result2.error;
|
||||||
|
}
|
||||||
6
server/app/worker/spec/nodemon.json
Normal file
6
server/app/worker/spec/nodemon.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"watch": ["spec"],
|
||||||
|
"ext": "spec.ts",
|
||||||
|
"ignore": ["spec/support"],
|
||||||
|
"exec": "./node_modules/.bin/ts-node -r tsconfig-paths/register ./spec"
|
||||||
|
}
|
||||||
11
server/app/worker/spec/support/jasmine.json
Normal file
11
server/app/worker/spec/support/jasmine.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"spec_dir": "spec",
|
||||||
|
"spec_files": [
|
||||||
|
"**/*[sS]pec.ts"
|
||||||
|
],
|
||||||
|
"helpers": [
|
||||||
|
"helpers/**/*.js"
|
||||||
|
],
|
||||||
|
"stopSpecOnExpectationFailure": false,
|
||||||
|
"random": true
|
||||||
|
}
|
||||||
14
server/app/worker/spec/support/types.ts
Normal file
14
server/app/worker/spec/support/types.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { Response } from 'supertest';
|
||||||
|
import { IUser } from '@entities/User';
|
||||||
|
|
||||||
|
|
||||||
|
export interface IResponse extends Response {
|
||||||
|
body: {
|
||||||
|
users: IUser[];
|
||||||
|
error: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IReqBody {
|
||||||
|
user?: IUser;
|
||||||
|
}
|
||||||
210
server/app/worker/spec/tests/Users.spec.ts
Normal file
210
server/app/worker/spec/tests/Users.spec.ts
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
import supertest from 'supertest';
|
||||||
|
import StatusCodes from 'http-status-codes';
|
||||||
|
import { SuperTest, Test } from 'supertest';
|
||||||
|
|
||||||
|
import app from '@server';
|
||||||
|
import UserDao from '@daos/User/UserDao.mock';
|
||||||
|
import User, { IUser } from '@entities/User';
|
||||||
|
import { pErr } from '@shared/functions';
|
||||||
|
import { paramMissingError } from '@shared/constants';
|
||||||
|
import { IReqBody, IResponse } from '../support/types';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
describe('Users Routes', () => {
|
||||||
|
|
||||||
|
const usersPath = '/api/users';
|
||||||
|
const getUsersPath = `${usersPath}/all`;
|
||||||
|
const addUsersPath = `${usersPath}/add`;
|
||||||
|
const updateUserPath = `${usersPath}/update`;
|
||||||
|
const deleteUserPath = `${usersPath}/delete/:id`;
|
||||||
|
|
||||||
|
const { BAD_REQUEST, CREATED, OK } = StatusCodes;
|
||||||
|
let agent: SuperTest<Test>;
|
||||||
|
|
||||||
|
beforeAll((done) => {
|
||||||
|
agent = supertest.agent(app);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`"GET:${getUsersPath}"`, () => {
|
||||||
|
|
||||||
|
it(`should return a JSON object with all the users and a status code of "${OK}" if the
|
||||||
|
request was successful.`, (done) => {
|
||||||
|
// Setup spy
|
||||||
|
const users = [
|
||||||
|
new User('Sean Maxwell', 'sean.maxwell@gmail.com'),
|
||||||
|
new User('John Smith', 'john.smith@gmail.com'),
|
||||||
|
new User('Gordan Freeman', 'gordan.freeman@gmail.com'),
|
||||||
|
];
|
||||||
|
spyOn(UserDao.prototype, 'getAll').and.returnValue(Promise.resolve(users));
|
||||||
|
// Call API
|
||||||
|
agent.get(getUsersPath)
|
||||||
|
.end((err: Error, res: IResponse) => {
|
||||||
|
pErr(err);
|
||||||
|
expect(res.status).toBe(OK);
|
||||||
|
// Caste instance-objects to 'User' objects
|
||||||
|
const respUsers = res.body.users;
|
||||||
|
const retUsers: User[] = respUsers.map((user: IUser) => {
|
||||||
|
return new User(user);
|
||||||
|
});
|
||||||
|
expect(retUsers).toEqual(users);
|
||||||
|
expect(res.body.error).toBeUndefined();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should return a JSON object containing an error message and a status code of
|
||||||
|
"${BAD_REQUEST}" if the request was unsuccessful.`, (done) => {
|
||||||
|
// Setup spy
|
||||||
|
const errMsg = 'Could not fetch users.';
|
||||||
|
spyOn(UserDao.prototype, 'getAll').and.throwError(errMsg);
|
||||||
|
// Call API
|
||||||
|
agent.get(getUsersPath)
|
||||||
|
.end((err: Error, res: IResponse) => {
|
||||||
|
pErr(err);
|
||||||
|
expect(res.status).toBe(BAD_REQUEST);
|
||||||
|
expect(res.body.error).toBe(errMsg);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe(`"POST:${addUsersPath}"`, () => {
|
||||||
|
|
||||||
|
const callApi = (reqBody: IReqBody) => {
|
||||||
|
return agent.post(addUsersPath).type('form').send(reqBody);
|
||||||
|
};
|
||||||
|
|
||||||
|
const userData = {
|
||||||
|
user: new User('Gordan Freeman', 'gordan.freeman@gmail.com'),
|
||||||
|
};
|
||||||
|
|
||||||
|
it(`should return a status code of "${CREATED}" if the request was successful.`, (done) => {
|
||||||
|
// Setup Spy
|
||||||
|
spyOn(UserDao.prototype, 'add').and.returnValue(Promise.resolve());
|
||||||
|
// Call API
|
||||||
|
agent.post(addUsersPath).type('form').send(userData)
|
||||||
|
.end((err: Error, res: IResponse) => {
|
||||||
|
pErr(err);
|
||||||
|
expect(res.status).toBe(CREATED);
|
||||||
|
expect(res.body.error).toBeUndefined();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should return a JSON object with an error message of "${paramMissingError}" and a status
|
||||||
|
code of "${BAD_REQUEST}" if the user param was missing.`, (done) => {
|
||||||
|
// Call API
|
||||||
|
callApi({})
|
||||||
|
.end((err: Error, res: IResponse) => {
|
||||||
|
pErr(err);
|
||||||
|
expect(res.status).toBe(BAD_REQUEST);
|
||||||
|
expect(res.body.error).toBe(paramMissingError);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should return a JSON object with an error message and a status code of "${BAD_REQUEST}"
|
||||||
|
if the request was unsuccessful.`, (done) => {
|
||||||
|
// Setup spy
|
||||||
|
const errMsg = 'Could not add user.';
|
||||||
|
spyOn(UserDao.prototype, 'add').and.throwError(errMsg);
|
||||||
|
// Call API
|
||||||
|
callApi(userData)
|
||||||
|
.end((err: Error, res: IResponse) => {
|
||||||
|
pErr(err);
|
||||||
|
expect(res.status).toBe(BAD_REQUEST);
|
||||||
|
expect(res.body.error).toBe(errMsg);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`"PUT:${updateUserPath}"`, () => {
|
||||||
|
|
||||||
|
const callApi = (reqBody: IReqBody) => {
|
||||||
|
return agent.put(updateUserPath).type('form').send(reqBody);
|
||||||
|
};
|
||||||
|
|
||||||
|
const userData = {
|
||||||
|
user: new User('Gordan Freeman', 'gordan.freeman@gmail.com'),
|
||||||
|
};
|
||||||
|
|
||||||
|
it(`should return a status code of "${OK}" if the request was successful.`, (done) => {
|
||||||
|
// Setup spy
|
||||||
|
spyOn(UserDao.prototype, 'update').and.returnValue(Promise.resolve());
|
||||||
|
// Call Api
|
||||||
|
callApi(userData)
|
||||||
|
.end((err: Error, res: IResponse) => {
|
||||||
|
pErr(err);
|
||||||
|
expect(res.status).toBe(OK);
|
||||||
|
expect(res.body.error).toBeUndefined();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should return a JSON object with an error message of "${paramMissingError}" and a
|
||||||
|
status code of "${BAD_REQUEST}" if the user param was missing.`, (done) => {
|
||||||
|
// Call api
|
||||||
|
callApi({})
|
||||||
|
.end((err: Error, res: IResponse) => {
|
||||||
|
pErr(err);
|
||||||
|
expect(res.status).toBe(BAD_REQUEST);
|
||||||
|
expect(res.body.error).toBe(paramMissingError);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should return a JSON object with an error message and a status code of "${BAD_REQUEST}"
|
||||||
|
if the request was unsuccessful.`, (done) => {
|
||||||
|
// Setup spy
|
||||||
|
const updateErrMsg = 'Could not update user.';
|
||||||
|
spyOn(UserDao.prototype, 'update').and.throwError(updateErrMsg);
|
||||||
|
// Call API
|
||||||
|
callApi(userData)
|
||||||
|
.end((err: Error, res: IResponse) => {
|
||||||
|
pErr(err);
|
||||||
|
expect(res.status).toBe(BAD_REQUEST);
|
||||||
|
expect(res.body.error).toBe(updateErrMsg);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`"DELETE:${deleteUserPath}"`, () => {
|
||||||
|
|
||||||
|
const callApi = (id: number) => {
|
||||||
|
return agent.delete(deleteUserPath.replace(':id', id.toString()));
|
||||||
|
};
|
||||||
|
|
||||||
|
it(`should return a status code of "${OK}" if the request was successful.`, (done) => {
|
||||||
|
// Setup spy
|
||||||
|
spyOn(UserDao.prototype, 'delete').and.returnValue(Promise.resolve());
|
||||||
|
// Call api
|
||||||
|
callApi(5)
|
||||||
|
.end((err: Error, res: IResponse) => {
|
||||||
|
pErr(err);
|
||||||
|
expect(res.status).toBe(OK);
|
||||||
|
expect(res.body.error).toBeUndefined();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should return a JSON object with an error message and a status code of "${BAD_REQUEST}"
|
||||||
|
if the request was unsuccessful.`, (done) => {
|
||||||
|
// Setup spy
|
||||||
|
const deleteErrMsg = 'Could not delete user.';
|
||||||
|
spyOn(UserDao.prototype, 'delete').and.throwError(deleteErrMsg);
|
||||||
|
// Call Api
|
||||||
|
callApi(1)
|
||||||
|
.end((err: Error, res: IResponse) => {
|
||||||
|
pErr(err);
|
||||||
|
expect(res.status).toBe(BAD_REQUEST);
|
||||||
|
expect(res.body.error).toBe(deleteErrMsg);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
63
server/app/worker/src/Server.ts
Normal file
63
server/app/worker/src/Server.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import cookieParser from 'cookie-parser';
|
||||||
|
import morgan from 'morgan';
|
||||||
|
import path from 'path';
|
||||||
|
import helmet from 'helmet';
|
||||||
|
|
||||||
|
import express, { NextFunction, Request, Response } from 'express';
|
||||||
|
import StatusCodes from 'http-status-codes';
|
||||||
|
import 'express-async-errors';
|
||||||
|
|
||||||
|
import BaseRouter from './routes';
|
||||||
|
import logger from '@shared/Logger';
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const { BAD_REQUEST } = StatusCodes;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************
|
||||||
|
* Set basic express settings
|
||||||
|
***********************************************************************************/
|
||||||
|
|
||||||
|
app.use(express.json());
|
||||||
|
app.use(express.urlencoded({extended: true}));
|
||||||
|
app.use(cookieParser());
|
||||||
|
|
||||||
|
// Show routes called in console during development
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
app.use(morgan('dev'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Security
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
app.use(helmet());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add APIs
|
||||||
|
app.use('/api', BaseRouter);
|
||||||
|
|
||||||
|
// Print API errors
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
|
||||||
|
logger.err(err, true);
|
||||||
|
return res.status(BAD_REQUEST).json({
|
||||||
|
error: err.message,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************
|
||||||
|
* Serve front-end content
|
||||||
|
***********************************************************************************/
|
||||||
|
|
||||||
|
const viewsDir = path.join(__dirname, 'views');
|
||||||
|
app.set('views', viewsDir);
|
||||||
|
const staticDir = path.join(__dirname, 'public');
|
||||||
|
app.use(express.static(staticDir));
|
||||||
|
app.get('*', (req: Request, res: Response) => {
|
||||||
|
res.sendFile('index.html', {root: viewsDir});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Export express instance
|
||||||
|
export default app;
|
||||||
25
server/app/worker/src/daos/MockDb/MockDao.mock.ts
Normal file
25
server/app/worker/src/daos/MockDb/MockDao.mock.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import jsonfile from 'jsonfile';
|
||||||
|
import { IUser } from '@entities/User';
|
||||||
|
|
||||||
|
|
||||||
|
interface IDatabase {
|
||||||
|
users: IUser[];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class MockDaoMock {
|
||||||
|
|
||||||
|
private readonly dbFilePath = 'src/daos/MockDb/MockDb.json';
|
||||||
|
|
||||||
|
|
||||||
|
protected openDb(): Promise<IDatabase> {
|
||||||
|
return jsonfile.readFile(this.dbFilePath) as Promise<IDatabase>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected saveDb(db: IDatabase): Promise<void> {
|
||||||
|
return jsonfile.writeFile(this.dbFilePath, db);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MockDaoMock;
|
||||||
19
server/app/worker/src/daos/MockDb/MockDb.backup.json
Normal file
19
server/app/worker/src/daos/MockDb/MockDb.backup.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"name": "Sean Maxwell",
|
||||||
|
"email": "sean.maxwell@gmail.com",
|
||||||
|
"id": 159123164363
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Gordan Freeman",
|
||||||
|
"email": "gordan.freeman@halflife.com",
|
||||||
|
"id": 906524522143
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "John Smith",
|
||||||
|
"email": "jsmith@yahoo.com",
|
||||||
|
"id": 357437875835
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
19
server/app/worker/src/daos/MockDb/MockDb.json
Normal file
19
server/app/worker/src/daos/MockDb/MockDb.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"name": "Sean Maxwell",
|
||||||
|
"email": "sean.maxwell@gmail.com",
|
||||||
|
"id": 159123164363
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Gordan Freeman",
|
||||||
|
"email": "gordan.freeman@halflife.com",
|
||||||
|
"id": 906524522143
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "John Smith",
|
||||||
|
"email": "jsmith@yahoo.com",
|
||||||
|
"id": 357437875835
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
62
server/app/worker/src/daos/User/UserDao.mock.ts
Normal file
62
server/app/worker/src/daos/User/UserDao.mock.ts
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import { IUser } from '@entities/User';
|
||||||
|
import { getRandomInt } from '@shared/functions';
|
||||||
|
import { IUserDao } from './UserDao';
|
||||||
|
import MockDaoMock from '../MockDb/MockDao.mock';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class UserDao extends MockDaoMock implements IUserDao {
|
||||||
|
|
||||||
|
|
||||||
|
public async getOne(email: string): Promise<IUser | null> {
|
||||||
|
const db = await super.openDb();
|
||||||
|
for (const user of db.users) {
|
||||||
|
if (user.email === email) {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async getAll(): Promise<IUser[]> {
|
||||||
|
const db = await super.openDb();
|
||||||
|
return db.users;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async add(user: IUser): Promise<void> {
|
||||||
|
const db = await super.openDb();
|
||||||
|
user.id = getRandomInt();
|
||||||
|
db.users.push(user);
|
||||||
|
await super.saveDb(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async update(user: IUser): Promise<void> {
|
||||||
|
const db = await super.openDb();
|
||||||
|
for (let i = 0; i < db.users.length; i++) {
|
||||||
|
if (db.users[i].id === user.id) {
|
||||||
|
db.users[i] = user;
|
||||||
|
await super.saveDb(db);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error('User not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async delete(id: number): Promise<void> {
|
||||||
|
const db = await super.openDb();
|
||||||
|
for (let i = 0; i < db.users.length; i++) {
|
||||||
|
if (db.users[i].id === id) {
|
||||||
|
db.users.splice(i, 1);
|
||||||
|
await super.saveDb(db);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error('User not found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserDao;
|
||||||
64
server/app/worker/src/daos/User/UserDao.ts
Normal file
64
server/app/worker/src/daos/User/UserDao.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import { IUser } from '@entities/User';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export interface IUserDao {
|
||||||
|
getOne: (email: string) => Promise<IUser | null>;
|
||||||
|
getAll: () => Promise<IUser[]>;
|
||||||
|
add: (user: IUser) => Promise<void>;
|
||||||
|
update: (user: IUser) => Promise<void>;
|
||||||
|
delete: (id: number) => Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
class UserDao implements IUserDao {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param email
|
||||||
|
*/
|
||||||
|
public getOne(email: string): Promise<IUser | null> {
|
||||||
|
// TODO
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public getAll(): Promise<IUser[]> {
|
||||||
|
// TODO
|
||||||
|
return Promise.resolve([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
*/
|
||||||
|
public async add(user: IUser): Promise<void> {
|
||||||
|
// TODO
|
||||||
|
return Promise.resolve(undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
*/
|
||||||
|
public async update(user: IUser): Promise<void> {
|
||||||
|
// TODO
|
||||||
|
return Promise.resolve(undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
public async delete(id: number): Promise<void> {
|
||||||
|
// TODO
|
||||||
|
return Promise.resolve(undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserDao;
|
||||||
26
server/app/worker/src/entities/User.ts
Normal file
26
server/app/worker/src/entities/User.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
export interface IUser {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class User implements IUser {
|
||||||
|
|
||||||
|
public id: number;
|
||||||
|
public name: string;
|
||||||
|
public email: string;
|
||||||
|
|
||||||
|
constructor(nameOrUser: string | IUser, email?: string, id?: number) {
|
||||||
|
if (typeof nameOrUser === 'string') {
|
||||||
|
this.name = nameOrUser;
|
||||||
|
this.email = email || '';
|
||||||
|
this.id = id || -1;
|
||||||
|
} else {
|
||||||
|
this.name = nameOrUser.name;
|
||||||
|
this.email = nameOrUser.email;
|
||||||
|
this.id = nameOrUser.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default User;
|
||||||
10
server/app/worker/src/index.ts
Normal file
10
server/app/worker/src/index.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import './pre-start'; // Must be the first import
|
||||||
|
import app from '@server';
|
||||||
|
import logger from '@shared/Logger';
|
||||||
|
|
||||||
|
|
||||||
|
// Start the server
|
||||||
|
const port = Number(process.env.PORT || 3000);
|
||||||
|
app.listen(port, () => {
|
||||||
|
logger.info('Express server started on port: ' + port);
|
||||||
|
});
|
||||||
14
server/app/worker/src/pre-start/env/development.env
vendored
Normal file
14
server/app/worker/src/pre-start/env/development.env
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
## Environment ##
|
||||||
|
NODE_ENV=development
|
||||||
|
|
||||||
|
|
||||||
|
## Server ##
|
||||||
|
PORT=3000
|
||||||
|
HOST=localhost
|
||||||
|
|
||||||
|
|
||||||
|
## Setup jet-logger ##
|
||||||
|
JET_LOGGER_MODE=CONSOLE
|
||||||
|
JET_LOGGER_FILEPATH=jet-logger.log
|
||||||
|
JET_LOGGER_TIMESTAMP=TRUE
|
||||||
|
JET_LOGGER_FORMAT=LINE
|
||||||
14
server/app/worker/src/pre-start/env/production.env
vendored
Normal file
14
server/app/worker/src/pre-start/env/production.env
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
## Environment ##
|
||||||
|
NODE_ENV=production
|
||||||
|
|
||||||
|
|
||||||
|
## Server ##
|
||||||
|
PORT=8081
|
||||||
|
HOST=localhost
|
||||||
|
|
||||||
|
|
||||||
|
## Setup jet-logger ##
|
||||||
|
JET_LOGGER_MODE=FILE
|
||||||
|
JET_LOGGER_FILEPATH=jet-logger.log
|
||||||
|
JET_LOGGER_TIMESTAMP=TRUE
|
||||||
|
JET_LOGGER_FORMAT=LINE
|
||||||
14
server/app/worker/src/pre-start/env/test.env
vendored
Normal file
14
server/app/worker/src/pre-start/env/test.env
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
## Environment ##
|
||||||
|
NODE_ENV=test
|
||||||
|
|
||||||
|
|
||||||
|
## Server ##
|
||||||
|
PORT=4000
|
||||||
|
HOST=localhost
|
||||||
|
|
||||||
|
|
||||||
|
## Setup jet-logger ##
|
||||||
|
JET_LOGGER_MODE=CONSOLE
|
||||||
|
JET_LOGGER_FILEPATH=jet-logger.log
|
||||||
|
JET_LOGGER_TIMESTAMP=TRUE
|
||||||
|
JET_LOGGER_FORMAT=LINE
|
||||||
29
server/app/worker/src/pre-start/index.ts
Normal file
29
server/app/worker/src/pre-start/index.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Pre-start is where we want to place things that must run BEFORE the express server is started.
|
||||||
|
* This is useful for environment variables, command-line arguments, and cron-jobs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import path from 'path';
|
||||||
|
import dotenv from 'dotenv';
|
||||||
|
import commandLineArgs from 'command-line-args';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(() => {
|
||||||
|
// Setup command line options
|
||||||
|
const options = commandLineArgs([
|
||||||
|
{
|
||||||
|
name: 'env',
|
||||||
|
alias: 'e',
|
||||||
|
defaultValue: 'development',
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
// Set the env file
|
||||||
|
const result2 = dotenv.config({
|
||||||
|
path: path.join(__dirname, `env/${options.env}.env`),
|
||||||
|
});
|
||||||
|
if (result2.error) {
|
||||||
|
throw result2.error;
|
||||||
|
}
|
||||||
|
})();
|
||||||
171
server/app/worker/src/public/scripts/index.js
Normal file
171
server/app/worker/src/public/scripts/index.js
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Fetch and display users
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
displayUsers();
|
||||||
|
|
||||||
|
|
||||||
|
function displayUsers() {
|
||||||
|
httpGet('/api/users/all')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then((response) => {
|
||||||
|
var allUsers = response.users;
|
||||||
|
// Empty the anchor
|
||||||
|
var allUsersAnchor = document.getElementById('all-users-anchor');
|
||||||
|
allUsersAnchor.innerHTML = '';
|
||||||
|
// Append users to anchor
|
||||||
|
allUsers.forEach((user) => {
|
||||||
|
allUsersAnchor.innerHTML += getUserDisplayEle(user);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function getUserDisplayEle(user) {
|
||||||
|
return `<div class="user-display-ele">
|
||||||
|
|
||||||
|
<div class="normal-view">
|
||||||
|
<div>Name: ${user.name}</div>
|
||||||
|
<div>Email: ${user.email}</div>
|
||||||
|
<button class="edit-user-btn" data-user-id="${user.id}">
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
<button class="delete-user-btn" data-user-id="${user.id}">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="edit-view">
|
||||||
|
<div>
|
||||||
|
Name: <input class="name-edit-input" value="${user.name}">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Email: <input class="email-edit-input" value="${user.email}">
|
||||||
|
</div>
|
||||||
|
<button class="submit-edit-btn" data-user-id="${user.id}">
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
<button class="cancel-edit-btn" data-user-id="${user.id}">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Add, Edit, and Delete Users
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
document.addEventListener('click', function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
var ele = event.target;
|
||||||
|
if (ele.matches('#add-user-btn')) {
|
||||||
|
addUser();
|
||||||
|
} else if (ele.matches('.edit-user-btn')) {
|
||||||
|
showEditView(ele.parentNode.parentNode);
|
||||||
|
} else if (ele.matches('.cancel-edit-btn')) {
|
||||||
|
cancelEdit(ele.parentNode.parentNode);
|
||||||
|
} else if (ele.matches('.submit-edit-btn')) {
|
||||||
|
submitEdit(ele);
|
||||||
|
} else if (ele.matches('.delete-user-btn')) {
|
||||||
|
deleteUser(ele);
|
||||||
|
}
|
||||||
|
}, false)
|
||||||
|
|
||||||
|
|
||||||
|
function addUser() {
|
||||||
|
var nameInput = document.getElementById('name-input');
|
||||||
|
var emailInput = document.getElementById('email-input');
|
||||||
|
var data = {
|
||||||
|
user: {
|
||||||
|
name: nameInput.value,
|
||||||
|
email: emailInput.value
|
||||||
|
},
|
||||||
|
};
|
||||||
|
httpPost('/api/users/add', data)
|
||||||
|
.then(() => {
|
||||||
|
displayUsers();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function showEditView(userEle) {
|
||||||
|
var normalView = userEle.getElementsByClassName('normal-view')[0];
|
||||||
|
var editView = userEle.getElementsByClassName('edit-view')[0];
|
||||||
|
normalView.style.display = 'none';
|
||||||
|
editView.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function cancelEdit(userEle) {
|
||||||
|
var normalView = userEle.getElementsByClassName('normal-view')[0];
|
||||||
|
var editView = userEle.getElementsByClassName('edit-view')[0];
|
||||||
|
normalView.style.display = 'block';
|
||||||
|
editView.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function submitEdit(ele) {
|
||||||
|
var userEle = ele.parentNode.parentNode;
|
||||||
|
var nameInput = userEle.getElementsByClassName('name-edit-input')[0];
|
||||||
|
var emailInput = userEle.getElementsByClassName('email-edit-input')[0];
|
||||||
|
var id = ele.getAttribute('data-user-id');
|
||||||
|
var data = {
|
||||||
|
user: {
|
||||||
|
name: nameInput.value,
|
||||||
|
email: emailInput.value,
|
||||||
|
id: id
|
||||||
|
}
|
||||||
|
};
|
||||||
|
httpPut('/api/users/update', data)
|
||||||
|
.then(() => {
|
||||||
|
displayUsers();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function deleteUser(ele) {
|
||||||
|
var id = ele.getAttribute('data-user-id');
|
||||||
|
httpDelete('/api/users/delete/' + id)
|
||||||
|
.then(() => {
|
||||||
|
displayUsers();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function httpGet(path) {
|
||||||
|
return fetch(path, getOptions('GET'))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function httpPost(path, data) {
|
||||||
|
return fetch(path, getOptions('POST', data));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function httpPut(path, data) {
|
||||||
|
return fetch(path, getOptions('PUT', data));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function httpDelete(path) {
|
||||||
|
return fetch(path, getOptions('DELETE'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getOptions(verb, data) {
|
||||||
|
var options = {
|
||||||
|
dataType: 'json',
|
||||||
|
method: verb,
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (data) {
|
||||||
|
options.body = JSON.stringify(data);
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
33
server/app/worker/src/public/stylesheets/style.css
Normal file
33
server/app/worker/src/public/stylesheets/style.css
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
body {
|
||||||
|
padding: 100px;
|
||||||
|
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .users-column {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 2em;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .users-column .column-header {
|
||||||
|
padding-bottom: 5px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .add-user-col input {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .users-column .user-display-ele {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .users-column .user-display-ele button {
|
||||||
|
margin-top: 2px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .users-column .user-display-ele .edit-view {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
75
server/app/worker/src/routes/Users.ts
Normal file
75
server/app/worker/src/routes/Users.ts
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import StatusCodes from 'http-status-codes';
|
||||||
|
import { Request, Response, Router } from 'express';
|
||||||
|
|
||||||
|
import UserDao from '@daos/User/UserDao.mock';
|
||||||
|
import { paramMissingError, IRequest } from '@shared/constants';
|
||||||
|
|
||||||
|
const router = Router();
|
||||||
|
const userDao = new UserDao();
|
||||||
|
const { BAD_REQUEST, CREATED, OK } = StatusCodes;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Get All Users - "GET /api/users/all"
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
router.get('/all', async (req: Request, res: Response) => {
|
||||||
|
const users = await userDao.getAll();
|
||||||
|
return res.status(OK).json({users});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Add One - "POST /api/users/add"
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
router.post('/add', async (req: IRequest, res: Response) => {
|
||||||
|
const { user } = req.body;
|
||||||
|
if (!user) {
|
||||||
|
return res.status(BAD_REQUEST).json({
|
||||||
|
error: paramMissingError,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await userDao.add(user);
|
||||||
|
return res.status(CREATED).end();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Update - "PUT /api/users/update"
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
router.put('/update', async (req: IRequest, res: Response) => {
|
||||||
|
const { user } = req.body;
|
||||||
|
if (!user) {
|
||||||
|
return res.status(BAD_REQUEST).json({
|
||||||
|
error: paramMissingError,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
user.id = Number(user.id);
|
||||||
|
await userDao.update(user);
|
||||||
|
return res.status(OK).end();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Delete - "DELETE /api/users/delete/:id"
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
router.delete('/delete/:id', async (req: IRequest, res: Response) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
await userDao.delete(Number(id));
|
||||||
|
return res.status(OK).end();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Export
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
export default router;
|
||||||
21
server/app/worker/src/routes/Worker.ts
Normal file
21
server/app/worker/src/routes/Worker.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import StatusCodes from 'http-status-codes';
|
||||||
|
import { Request, Response, Router } from 'express';
|
||||||
|
import { IWorkerMessage } from "domain-worker/IWorkerMessage";
|
||||||
|
|
||||||
|
const router = Router();
|
||||||
|
const { OK } = StatusCodes;
|
||||||
|
|
||||||
|
router.get('/all', async (req: Request, res: Response<Array<IWorkerMessage<any>>>) => {
|
||||||
|
console.log('hit')
|
||||||
|
return res.status(OK).json([{
|
||||||
|
name: "yo",
|
||||||
|
payload: {
|
||||||
|
type: "message",
|
||||||
|
value: {
|
||||||
|
data: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
||||||
13
server/app/worker/src/routes/index.ts
Normal file
13
server/app/worker/src/routes/index.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { Router } from 'express';
|
||||||
|
import UserRouter from './Users';
|
||||||
|
import WorkerRouter from './Worker';
|
||||||
|
|
||||||
|
// Init router and path
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
// Add sub-routes
|
||||||
|
router.use('/users', UserRouter);
|
||||||
|
router.use('/worker', WorkerRouter);
|
||||||
|
|
||||||
|
// Export the base-router
|
||||||
|
export default router;
|
||||||
12
server/app/worker/src/shared/Logger.ts
Normal file
12
server/app/worker/src/shared/Logger.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* Setup the jet-logger.
|
||||||
|
*
|
||||||
|
* Documentation: https://github.com/seanpmaxwell/jet-logger
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Logger from 'jet-logger';
|
||||||
|
|
||||||
|
|
||||||
|
const logger = new Logger();
|
||||||
|
|
||||||
|
export default logger;
|
||||||
11
server/app/worker/src/shared/constants.ts
Normal file
11
server/app/worker/src/shared/constants.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { Request } from 'express';
|
||||||
|
import { IUser } from '@entities/User';
|
||||||
|
|
||||||
|
|
||||||
|
export const paramMissingError = 'One or more of the required parameters was missing.';
|
||||||
|
|
||||||
|
export interface IRequest extends Request {
|
||||||
|
body: {
|
||||||
|
user: IUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
server/app/worker/src/shared/functions.ts
Normal file
11
server/app/worker/src/shared/functions.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import logger from './Logger';
|
||||||
|
|
||||||
|
export const pErr = (err: Error) => {
|
||||||
|
if (err) {
|
||||||
|
logger.err(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getRandomInt = () => {
|
||||||
|
return Math.floor(Math.random() * 1_000_000_000_000);
|
||||||
|
};
|
||||||
34
server/app/worker/src/views/index.html
Normal file
34
server/app/worker/src/views/index.html
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>ExpressGeneratorTypeScriptApp</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/stylesheets/style.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<!-- Add Users -->
|
||||||
|
<div class="users-column add-user-col">
|
||||||
|
<div class="column-header">Add User:</div>
|
||||||
|
<div>
|
||||||
|
<input id="name-input" placeholder="Name">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input id="email-input" placeholder="Email">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button id="add-user-btn">Add</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Display Users -->
|
||||||
|
<div class="users-column">
|
||||||
|
<div class="column-header">Users:</div>
|
||||||
|
<div id="all-users-anchor"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
<script src="scripts/index.js"></script>
|
||||||
|
</html>
|
||||||
90
server/app/worker/tsconfig.json
Normal file
90
server/app/worker/tsconfig.json
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||||
|
|
||||||
|
/* Basic Options */
|
||||||
|
// "incremental": true, /* Enable incremental compilation */
|
||||||
|
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
|
||||||
|
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||||
|
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||||
|
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||||
|
// "checkJs": true, /* Report errors in .js files. */
|
||||||
|
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||||
|
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||||
|
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||||
|
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||||
|
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||||
|
"outDir": "dist", /* Redirect output structure to the directory. */
|
||||||
|
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||||
|
// "composite": true, /* Enable project compilation */
|
||||||
|
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||||
|
// "removeComments": true, /* Do not emit comments to output. */
|
||||||
|
// "noEmit": true, /* Do not emit outputs. */
|
||||||
|
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||||
|
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||||
|
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||||
|
|
||||||
|
/* Strict Type-Checking Options */
|
||||||
|
"strict": true, /* Enable all strict type-checking options. */
|
||||||
|
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||||
|
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||||
|
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||||
|
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||||
|
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
||||||
|
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||||
|
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||||
|
|
||||||
|
/* Additional Checks */
|
||||||
|
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
||||||
|
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||||
|
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||||
|
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||||
|
|
||||||
|
/* Module Resolution Options */
|
||||||
|
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||||
|
"baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||||
|
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||||
|
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||||
|
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||||
|
// "types": [], /* Type declaration files to be included in compilation. */
|
||||||
|
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||||
|
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||||
|
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||||
|
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||||
|
|
||||||
|
/* Source Map Options */
|
||||||
|
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||||
|
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||||
|
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||||
|
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||||
|
|
||||||
|
/* Experimental Options */
|
||||||
|
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||||
|
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||||
|
|
||||||
|
/* Advanced Options */
|
||||||
|
"skipLibCheck": true, /* Skip type checking of declaration files. */
|
||||||
|
"forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
|
||||||
|
"paths": {
|
||||||
|
"@daos/*": [
|
||||||
|
"src/daos/*"
|
||||||
|
],
|
||||||
|
"@entities/*": [
|
||||||
|
"src/entities/*"
|
||||||
|
],
|
||||||
|
"@shared/*": [
|
||||||
|
"src/shared/*"
|
||||||
|
],
|
||||||
|
"@server": [
|
||||||
|
"src/Server"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"spec/**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"src/public/"
|
||||||
|
]
|
||||||
|
}
|
||||||
11
server/app/worker/tsconfig.prod.json
Normal file
11
server/app/worker/tsconfig.prod.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"sourceMap": false
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"spec",
|
||||||
|
"src/**/*.mock.ts",
|
||||||
|
"src/public/"
|
||||||
|
]
|
||||||
|
}
|
||||||
2458
server/app/worker/yarn.lock
Normal file
2458
server/app/worker/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
7
server/lib/domain-worker/IWorkerMessage.ts
Normal file
7
server/lib/domain-worker/IWorkerMessage.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export interface IWorkerMessage<T> {
|
||||||
|
name: String,
|
||||||
|
payload: {
|
||||||
|
type: String,
|
||||||
|
value: T
|
||||||
|
}
|
||||||
|
}
|
||||||
6
server/lib/domain-worker/package.json
Normal file
6
server/lib/domain-worker/package.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "domain-worker",
|
||||||
|
"description": "",
|
||||||
|
"authors": "",
|
||||||
|
"version": "1.0.0"
|
||||||
|
}
|
||||||
@@ -2,10 +2,11 @@
|
|||||||
"name": "server",
|
"name": "server",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"private": true,
|
||||||
"workspaces": {
|
"workspaces": {
|
||||||
"packages": [
|
"packages": [
|
||||||
"lib/*",
|
"app/*",
|
||||||
"apps/*"
|
"lib/*"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2928
server/yarn.lock
Normal file
2928
server/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user