express-generator-typescript 2.3.7 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -34
- package/bin/cli.js +22 -7
- package/lib/cli.js +22 -7
- package/lib/express-generator-typescript.js +38 -28
- package/lib/project-files/spec/tests/users.spec.ts +9 -20
- package/lib/project-files/src/models/User.ts +50 -53
- package/lib/project-files/src/repos/database.json +1 -1
- package/lib/project-files/src/routes/api.ts +1 -24
- package/lib/project-files/src/routes/constants/Paths.ts +0 -5
- package/lib/project-files/src/server.ts +4 -9
- package/lib/project-files/src/views/users.html +0 -5
- package/lib/project-files-auth/.eslintignore +1 -0
- package/lib/project-files-auth/.eslintrc.json +44 -0
- package/lib/project-files-auth/README.md +43 -0
- package/lib/project-files-auth/build.ts +64 -0
- package/lib/project-files-auth/env/development.env +24 -0
- package/lib/project-files-auth/env/production.env +25 -0
- package/lib/project-files-auth/env/test.env +24 -0
- package/lib/project-files-auth/gitignore +3 -0
- package/lib/project-files-auth/package.json +70 -0
- package/lib/project-files-auth/spec/index.ts +77 -0
- package/lib/project-files-auth/spec/nodemon.json +6 -0
- package/lib/project-files-auth/spec/support/jasmine.json +11 -0
- package/lib/{project-files → project-files-auth}/spec/support/login.ts +1 -1
- package/lib/project-files-auth/spec/support/types.ts +1 -0
- package/lib/{project-files → project-files-auth}/spec/tests/auth.spec.ts +2 -2
- package/lib/project-files-auth/spec/tests/users.spec.ts +224 -0
- package/lib/project-files-auth/spec/types/supertest/index.d.ts +14 -0
- package/lib/project-files-auth/src/constants/EnvVars.ts +28 -0
- package/lib/project-files-auth/src/constants/HttpStatusCodes.ts +386 -0
- package/lib/project-files-auth/src/constants/misc.ts +5 -0
- package/lib/project-files-auth/src/index.ts +13 -0
- package/lib/project-files-auth/src/models/User.ts +85 -0
- package/lib/project-files-auth/src/other/classes.ts +17 -0
- package/lib/project-files-auth/src/other/types.ts +4 -0
- package/lib/project-files-auth/src/pre-start.ts +37 -0
- package/lib/project-files-auth/src/public/scripts/http.js +24 -0
- package/lib/project-files-auth/src/public/scripts/users.js +164 -0
- package/lib/project-files-auth/src/public/stylesheets/users.css +50 -0
- package/lib/project-files-auth/src/repos/MockOrm.ts +42 -0
- package/lib/project-files-auth/src/repos/UserRepo.ts +88 -0
- package/lib/project-files-auth/src/repos/database.json +1 -0
- package/lib/project-files-auth/src/routes/UserRoutes.ts +53 -0
- package/lib/project-files-auth/src/routes/api.ts +75 -0
- package/lib/project-files-auth/src/routes/constants/FullPaths.ts +40 -0
- package/lib/project-files-auth/src/routes/constants/Paths.ts +28 -0
- package/lib/project-files-auth/src/routes/types/express/index.d.ts +11 -0
- package/lib/project-files-auth/src/routes/types/express/misc.ts +16 -0
- package/lib/project-files-auth/src/routes/types/types.ts +22 -0
- package/lib/project-files-auth/src/server.ts +96 -0
- package/lib/project-files-auth/src/services/AuthService.ts +56 -0
- package/lib/project-files-auth/src/services/UserService.ts +66 -0
- package/lib/project-files-auth/src/util/PwdUtil.ts +39 -0
- package/lib/project-files-auth/src/util/SessionUtil.ts +92 -0
- package/lib/project-files-auth/src/util/misc.ts +22 -0
- package/lib/project-files-auth/src/views/users.html +42 -0
- package/lib/project-files-auth/tsconfig.json +83 -0
- package/lib/project-files-auth/tsconfig.prod.json +12 -0
- package/package.json +1 -1
- /package/lib/{project-files → project-files-auth}/src/public/scripts/login.js +0 -0
- /package/lib/{project-files → project-files-auth}/src/public/stylesheets/login.css +0 -0
- /package/lib/{project-files → project-files-auth}/src/routes/AuthRoutes.ts +0 -0
- /package/lib/{project-files → project-files-auth}/src/routes/middleware/adminMw.ts +0 -0
- /package/lib/{project-files → project-files-auth}/src/views/login.html +0 -0
package/README.md
CHANGED
|
@@ -39,9 +39,9 @@ and `_moduleAliases` in _package.json_ if you want to add/edit the relative path
|
|
|
39
39
|
|
|
40
40
|
When you run _express-generator-typescript_, it sets up a simple application with routes for
|
|
41
41
|
adding, updating, deleting, and fetching user objects. This is just to demonstrate how routing is done
|
|
42
|
-
with express.
|
|
43
|
-
|
|
44
|
-
to store user-session data.
|
|
42
|
+
with express.
|
|
43
|
+
|
|
44
|
+
If you want a fully-secure application, you can pass the `--with-auth` option and you will have an application which requires you to login before calling APIs on user objects. The app is configured with production quality client-side security and uses signed-cookies and jsonwebtokens to store user-session data. If you're new to web-development and still learning about securing websites, I highly encourage to use this option.
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
## Installation
|
|
@@ -60,10 +60,9 @@ If you don't specify a project name, the default _express-gen-ts_ will be used i
|
|
|
60
60
|
want to use `yarn` instead of `npm`, pass the option `--use-yarn`.
|
|
61
61
|
|
|
62
62
|
Create the app:
|
|
63
|
+
With no options: `$ npx express-generator-typescript`
|
|
64
|
+
With all options (order doesn't matter): `$ npx express-generator-typescript --with-auth --use-yarn "project name"`
|
|
63
65
|
|
|
64
|
-
```bash
|
|
65
|
-
$ npx express-generator-typescript "project name (default is express-gen-ts)"
|
|
66
|
-
```
|
|
67
66
|
|
|
68
67
|
Start your express-generator-typescript app in development mode at `http://localhost:3000/`:
|
|
69
68
|
|
|
@@ -92,34 +91,6 @@ This is located under `nodemonConfig:` in `package.json` for the server and `./s
|
|
|
92
91
|
unit-testing. For the `exec` property, replace `ts-node` with `node --inspect -r ts-node/register`.
|
|
93
92
|
|
|
94
93
|
|
|
95
|
-
## If you don't want authentication:
|
|
96
|
-
|
|
97
|
-
In previous version of __express-generator-typescript__ you could disregard authentication through the
|
|
98
|
-
command line options. But maintaining two separate project folders which contained and didn't contain
|
|
99
|
-
authentication started to get messy.
|
|
100
|
-
|
|
101
|
-
- Remove the following modules from `package.json`:
|
|
102
|
-
- `jsonwebtoken`
|
|
103
|
-
- `@types/jsonwebtoken`
|
|
104
|
-
- `bcrypt`
|
|
105
|
-
- `@types/bcrypt`
|
|
106
|
-
|
|
107
|
-
- Delete the files:
|
|
108
|
-
- `src/routes/middleware.ts`
|
|
109
|
-
- `src/routes/auth-router.ts`
|
|
110
|
-
- `spec/tests/auth.spec.ts`
|
|
111
|
-
- `spec/support/login-agent.ts`
|
|
112
|
-
- `public/scripts/login.js`
|
|
113
|
-
- `public/stylesheets/login.css`
|
|
114
|
-
- `public/views/login.html`
|
|
115
|
-
|
|
116
|
-
- Update the files:
|
|
117
|
-
- In `src/routes/api`, delete the line: `apiRouter.use('/auth', authRouter);` and
|
|
118
|
-
remove the `adminMw,` from line 12. Remove the `adminMw` and `authRouter` imports as well.
|
|
119
|
-
- In `spec/tests/users.spec.ts`, remove all lines containing `loginAgent` and `setCookie`
|
|
120
|
-
- In `public/views/users.html` remove the `Logout` button.
|
|
121
|
-
|
|
122
|
-
|
|
123
94
|
## Note for VS-Code users
|
|
124
95
|
|
|
125
96
|
A lot of users have asked about _launch.json_ configurations for running this in VS-Code, so
|
package/bin/cli.js
CHANGED
|
@@ -10,17 +10,29 @@ const path = require('path');
|
|
|
10
10
|
const expressGenTs = require('../lib/express-generator-typescript');
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
// Start
|
|
13
|
+
// **** Start **** //
|
|
14
|
+
|
|
14
15
|
console.log('Setting up new Express/TypeScript project...');
|
|
15
16
|
|
|
17
|
+
|
|
18
|
+
// **** Process Options **** //
|
|
19
|
+
|
|
20
|
+
const args = process.argv.slice(2);
|
|
21
|
+
|
|
16
22
|
// Setup use yarn
|
|
17
23
|
let useYarn = false;
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
idx = args.indexOf('--use-yarn');
|
|
21
|
-
if (idx > -1) {
|
|
24
|
+
const useYarnIdx = args.indexOf('--use-yarn');
|
|
25
|
+
if (useYarnIdx > -1) {
|
|
22
26
|
useYarn = true;
|
|
23
|
-
args.splice(
|
|
27
|
+
args.splice(useYarnIdx, 1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Setup include authentication
|
|
31
|
+
let withAuth = false;
|
|
32
|
+
const withAuthIdx = args.indexOf('--with-auth');
|
|
33
|
+
if (withAuthIdx > -1) {
|
|
34
|
+
withAuth = true;
|
|
35
|
+
args.splice(withAuthIdx, 1);
|
|
24
36
|
}
|
|
25
37
|
|
|
26
38
|
// Setup destination
|
|
@@ -30,7 +42,10 @@ if (args.length > 0) {
|
|
|
30
42
|
}
|
|
31
43
|
destination = path.join(process.cwd(), destination);
|
|
32
44
|
|
|
45
|
+
|
|
46
|
+
// **** Call the generator script **** //
|
|
47
|
+
|
|
33
48
|
// Creating new project finished
|
|
34
|
-
expressGenTs(destination, useYarn).then(() => {
|
|
49
|
+
expressGenTs(destination, useYarn, withAuth).then(() => {
|
|
35
50
|
console.log('Project setup complete!');
|
|
36
51
|
});
|
package/lib/cli.js
CHANGED
|
@@ -10,17 +10,29 @@ const path = require('path');
|
|
|
10
10
|
const expressGenTs = require('../lib/express-generator-typescript');
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
// Start
|
|
13
|
+
// **** Start **** //
|
|
14
|
+
|
|
14
15
|
console.log('Setting up new Express/TypeScript project...');
|
|
15
16
|
|
|
17
|
+
|
|
18
|
+
// **** Process Options **** //
|
|
19
|
+
|
|
20
|
+
const args = process.argv.slice(2);
|
|
21
|
+
|
|
16
22
|
// Setup use yarn
|
|
17
23
|
let useYarn = false;
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
idx = args.indexOf('--use-yarn');
|
|
21
|
-
if (idx > -1) {
|
|
24
|
+
const useYarnIdx = args.indexOf('--use-yarn');
|
|
25
|
+
if (useYarnIdx > -1) {
|
|
22
26
|
useYarn = true;
|
|
23
|
-
args.splice(
|
|
27
|
+
args.splice(useYarnIdx, 1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Setup include authentication
|
|
31
|
+
let withAuth = false;
|
|
32
|
+
const withAuthIdx = args.indexOf('--with-auth');
|
|
33
|
+
if (withAuthIdx > -1) {
|
|
34
|
+
withAuth = true;
|
|
35
|
+
args.splice(withAuthIdx, 1);
|
|
24
36
|
}
|
|
25
37
|
|
|
26
38
|
// Setup destination
|
|
@@ -30,7 +42,10 @@ if (args.length > 0) {
|
|
|
30
42
|
}
|
|
31
43
|
destination = path.join(process.cwd(), destination);
|
|
32
44
|
|
|
45
|
+
|
|
46
|
+
// **** Call the generator script **** //
|
|
47
|
+
|
|
33
48
|
// Creating new project finished
|
|
34
|
-
expressGenTs(destination, useYarn).then(() => {
|
|
49
|
+
expressGenTs(destination, useYarn, withAuth).then(() => {
|
|
35
50
|
console.log('Project setup complete!');
|
|
36
51
|
});
|
|
@@ -13,41 +13,41 @@ const path = require('path'),
|
|
|
13
13
|
|
|
14
14
|
// **** Variables **** //
|
|
15
15
|
|
|
16
|
-
//
|
|
16
|
+
// Project folder paths
|
|
17
17
|
const PROJECT_FOLDER_PATH = './project-files';
|
|
18
|
+
PROJECT_FOLDER_PATH_AUTH = './project-files-auth';
|
|
18
19
|
|
|
19
|
-
//
|
|
20
|
+
// Project-folder dependencies
|
|
21
|
+
const DEPENDENCIES = 'express dotenv morgan cookie-parser jet-logger ' +
|
|
22
|
+
'module-alias express-async-errors helmet jsonfile inserturlparams ' +
|
|
23
|
+
'jet-validator ts-command-line-args',
|
|
24
|
+
DEPENDENCIES_AUTH = ' bcrypt jsonwebtoken',
|
|
25
|
+
DEV_DEPENDENCIES = 'ts-node typescript nodemon find jasmine supertest ' +
|
|
26
|
+
'@types/node @types/express @types/jasmine @types/find @types/morgan ' +
|
|
27
|
+
'@types/cookie-parser @types/supertest fs-extra tsconfig-paths ' +
|
|
28
|
+
'@types/jsonfile @typescript-eslint/eslint-plugin eslint ' +
|
|
29
|
+
'@typescript-eslint/parser @types/fs-extra eslint-plugin-node',
|
|
30
|
+
DEV_DEPENDENCIES_AUTH = ' @types/bcrypt @types/jsonwebtoken';
|
|
31
|
+
|
|
32
|
+
// "ncp" options
|
|
20
33
|
const ncpOpts = {
|
|
21
34
|
filter: (fileName) => {
|
|
22
35
|
return !(fileName === 'package-lock.json' || fileName === 'node_modules');
|
|
23
36
|
},
|
|
24
37
|
};
|
|
25
38
|
|
|
26
|
-
// Project-folder dependencies
|
|
27
|
-
const dependencies = 'express dotenv morgan cookie-parser jet-logger ' +
|
|
28
|
-
'module-alias express-async-errors helmet jsonfile inserturlparams ' +
|
|
29
|
-
'bcrypt jsonwebtoken jet-validator ts-command-line-args';
|
|
30
|
-
|
|
31
|
-
// Project-folder development dependencies
|
|
32
|
-
const devDependencies = 'ts-node typescript nodemon find jasmine supertest ' +
|
|
33
|
-
'@types/node @types/express @types/jasmine @types/find @types/morgan ' +
|
|
34
|
-
'@types/cookie-parser @types/supertest fs-extra tsconfig-paths ' +
|
|
35
|
-
'@types/jsonfile @typescript-eslint/eslint-plugin eslint ' +
|
|
36
|
-
'@typescript-eslint/parser @types/fs-extra @types/bcrypt ' +
|
|
37
|
-
'@types/jsonwebtoken eslint-plugin-node';
|
|
38
|
-
|
|
39
39
|
|
|
40
40
|
// **** Functions **** //
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* Entry point
|
|
44
44
|
*/
|
|
45
|
-
async function expressGenTs(destination, useYarn) {
|
|
45
|
+
async function expressGenTs(destination, useYarn, withAuth) {
|
|
46
46
|
try {
|
|
47
|
-
await copyProjectFiles(destination);
|
|
47
|
+
await copyProjectFiles(destination, withAuth);
|
|
48
48
|
updatePackageJson(destination);
|
|
49
49
|
await renameGitigoreFile(destination);
|
|
50
|
-
downloadNodeModules(destination, useYarn);
|
|
50
|
+
downloadNodeModules(destination, useYarn, withAuth);
|
|
51
51
|
} catch (err) {
|
|
52
52
|
console.error(err);
|
|
53
53
|
}
|
|
@@ -56,8 +56,9 @@ async function expressGenTs(destination, useYarn) {
|
|
|
56
56
|
/**
|
|
57
57
|
* Copy project files
|
|
58
58
|
*/
|
|
59
|
-
function copyProjectFiles(destination) {
|
|
60
|
-
const
|
|
59
|
+
function copyProjectFiles(destination, withAuth) {
|
|
60
|
+
const folder = (withAuth ? PROJECT_FOLDER_PATH_AUTH : PROJECT_FOLDER_PATH),
|
|
61
|
+
source = path.join(__dirname, folder);
|
|
61
62
|
return new Promise((res, rej) => {
|
|
62
63
|
ncp.limit = 16;
|
|
63
64
|
return ncp(source, destination, ncpOpts, (err) => {
|
|
@@ -94,17 +95,26 @@ function renameGitigoreFile(destination) {
|
|
|
94
95
|
/**
|
|
95
96
|
* Download the dependencies.
|
|
96
97
|
*/
|
|
97
|
-
function downloadNodeModules(destination, useYarn) {
|
|
98
|
-
const options = {cwd: destination};
|
|
99
|
-
|
|
100
|
-
let
|
|
98
|
+
function downloadNodeModules(destination, useYarn, withAuth) {
|
|
99
|
+
const options = { cwd: destination };
|
|
100
|
+
// Setup dependencies string
|
|
101
|
+
let depStr = DEPENDENCIES,
|
|
102
|
+
devDepStr = DEV_DEPENDENCIES;
|
|
103
|
+
if (withAuth) {
|
|
104
|
+
depStr += DEPENDENCIES_AUTH;
|
|
105
|
+
devDepStr += DEV_DEPENDENCIES_AUTH;
|
|
106
|
+
}
|
|
107
|
+
// Setup download command
|
|
108
|
+
let downloadLibCmd,
|
|
109
|
+
downloadDepCmd;
|
|
101
110
|
if (useYarn) {
|
|
102
|
-
downloadLibCmd = 'yarn add ' +
|
|
103
|
-
downloadDepCmd = 'yarn add ' +
|
|
111
|
+
downloadLibCmd = 'yarn add ' + depStr;
|
|
112
|
+
downloadDepCmd = 'yarn add ' + devDepStr + ' -D';
|
|
104
113
|
} else {
|
|
105
|
-
downloadLibCmd = 'npm i -s ' +
|
|
106
|
-
downloadDepCmd = 'npm i -D ' +
|
|
114
|
+
downloadLibCmd = 'npm i -s ' + depStr;
|
|
115
|
+
downloadDepCmd = 'npm i -D ' + devDepStr;
|
|
107
116
|
}
|
|
117
|
+
// Execute command
|
|
108
118
|
childProcess.execSync(downloadLibCmd, options);
|
|
109
119
|
childProcess.execSync(downloadDepCmd, options);
|
|
110
120
|
}
|
|
@@ -10,7 +10,6 @@ import HttpStatusCodes from '@src/constants/HttpStatusCodes';
|
|
|
10
10
|
import { USER_NOT_FOUND_ERR } from '@src/services/UserService';
|
|
11
11
|
import FullPaths from '@src/routes/constants/FullPaths';
|
|
12
12
|
|
|
13
|
-
import login from '../support/login';
|
|
14
13
|
import { TReqBody } from 'spec/support/types';
|
|
15
14
|
|
|
16
15
|
|
|
@@ -34,14 +33,14 @@ const {
|
|
|
34
33
|
|
|
35
34
|
// Dummy users for GET req
|
|
36
35
|
const DummyGetAllUsers = [
|
|
37
|
-
new
|
|
38
|
-
new
|
|
39
|
-
new
|
|
36
|
+
User.new('Sean Maxwell', 'sean.maxwell@gmail.com'),
|
|
37
|
+
User.new('John Smith', 'john.smith@gmail.com'),
|
|
38
|
+
User.new('Gordan Freeman', 'gordan.freeman@gmail.com'),
|
|
40
39
|
] as const;
|
|
41
40
|
|
|
42
41
|
// Dummy update user
|
|
43
42
|
const DummyUserData = {
|
|
44
|
-
user: new
|
|
43
|
+
user: User.new('Gordan Freeman', 'gordan.freeman@gmail.com'),
|
|
45
44
|
} as const;
|
|
46
45
|
|
|
47
46
|
|
|
@@ -49,25 +48,18 @@ const DummyUserData = {
|
|
|
49
48
|
|
|
50
49
|
describe('UserRouter', () => {
|
|
51
50
|
|
|
52
|
-
let agent: SuperTest<Test
|
|
53
|
-
jwtCookie: string;
|
|
51
|
+
let agent: SuperTest<Test>;
|
|
54
52
|
|
|
55
53
|
// Run before all tests
|
|
56
54
|
beforeAll((done) => {
|
|
57
55
|
agent = supertest.agent(app);
|
|
58
|
-
|
|
59
|
-
jwtCookie = cookie;
|
|
60
|
-
done();
|
|
61
|
-
});
|
|
56
|
+
done();
|
|
62
57
|
});
|
|
63
58
|
|
|
64
59
|
// ** Get all users ** //
|
|
65
60
|
describe(`"GET:${Get}"`, () => {
|
|
66
61
|
|
|
67
|
-
const callApi = () =>
|
|
68
|
-
agent
|
|
69
|
-
.get(Get)
|
|
70
|
-
.set('Cookie', jwtCookie);
|
|
62
|
+
const callApi = () => agent.get(Get);
|
|
71
63
|
|
|
72
64
|
// Success
|
|
73
65
|
it('should return a JSON object with all the users and a status code ' +
|
|
@@ -79,7 +71,7 @@ describe('UserRouter', () => {
|
|
|
79
71
|
.end((_: Error, res: Response) => {
|
|
80
72
|
expect(res.status).toBe(OK);
|
|
81
73
|
for (let i = 0; i < res.body.users.length; i++) {
|
|
82
|
-
const user =
|
|
74
|
+
const user = res.body.users[i];
|
|
83
75
|
expect(user).toEqual(DummyGetAllUsers[i]);
|
|
84
76
|
}
|
|
85
77
|
done();
|
|
@@ -93,7 +85,6 @@ describe('UserRouter', () => {
|
|
|
93
85
|
const callApi = (reqBody: TReqBody) =>
|
|
94
86
|
agent
|
|
95
87
|
.post(Add)
|
|
96
|
-
.set('Cookie', jwtCookie)
|
|
97
88
|
.type('form').send(reqBody);
|
|
98
89
|
|
|
99
90
|
// Test add user success
|
|
@@ -130,7 +121,6 @@ describe('UserRouter', () => {
|
|
|
130
121
|
const callApi = (reqBody: TReqBody) =>
|
|
131
122
|
agent
|
|
132
123
|
.put(Update)
|
|
133
|
-
.set('Cookie', jwtCookie)
|
|
134
124
|
.type('form').send(reqBody);
|
|
135
125
|
|
|
136
126
|
// Success
|
|
@@ -180,8 +170,7 @@ describe('UserRouter', () => {
|
|
|
180
170
|
|
|
181
171
|
const callApi = (id: number) =>
|
|
182
172
|
agent
|
|
183
|
-
.delete(insertUrlParams(Delete, { id }))
|
|
184
|
-
.set('Cookie', jwtCookie);
|
|
173
|
+
.delete(insertUrlParams(Delete, { id }));
|
|
185
174
|
|
|
186
175
|
// Success
|
|
187
176
|
it(`should return a status code of "${OK}" if the request was successful.`,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// **** Variables **** //
|
|
2
2
|
|
|
3
|
-
const INVALID_CONSTRUCTOR_PARAM = 'nameOrObj arg must a string or an
|
|
4
|
-
'with the appropriate user keys.';
|
|
3
|
+
const INVALID_CONSTRUCTOR_PARAM = 'nameOrObj arg must a string or an ' +
|
|
4
|
+
'object with the appropriate user keys.';
|
|
5
5
|
|
|
6
6
|
export enum UserRoles {
|
|
7
7
|
Standard,
|
|
@@ -27,62 +27,59 @@ export interface ISessionUser {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
// ****
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
name
|
|
45
|
-
email
|
|
46
|
-
role
|
|
47
|
-
pwdHash
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
this.name = (name ?? '');
|
|
51
|
-
this.email = (email ?? '');
|
|
52
|
-
this.role = (role ?? UserRoles.Standard);
|
|
53
|
-
this.pwdHash = (pwdHash ?? '');
|
|
54
|
-
this.id = (id ?? -1);
|
|
55
|
-
}
|
|
30
|
+
// **** Functions **** //
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Create new User.
|
|
34
|
+
*/
|
|
35
|
+
function new_(
|
|
36
|
+
name?: string,
|
|
37
|
+
email?: string,
|
|
38
|
+
role?: UserRoles,
|
|
39
|
+
pwdHash?: string,
|
|
40
|
+
id?: number, // id last cause usually set by db
|
|
41
|
+
): IUser {
|
|
42
|
+
return {
|
|
43
|
+
id: (id ?? -1),
|
|
44
|
+
name: (name ?? ''),
|
|
45
|
+
email: (email ?? ''),
|
|
46
|
+
role: (role ?? UserRoles.Standard),
|
|
47
|
+
pwdHash: (pwdHash ?? ''),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
56
50
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
// Get user instance
|
|
66
|
-
const p = param as IUser;
|
|
67
|
-
return new User(p.name, p.email, p.role, p.pwdHash, p.id);
|
|
51
|
+
/**
|
|
52
|
+
* Get user instance from object.
|
|
53
|
+
*/
|
|
54
|
+
function from(param: object): IUser {
|
|
55
|
+
// Check is user
|
|
56
|
+
if (!isUser(param)) {
|
|
57
|
+
throw new Error(INVALID_CONSTRUCTOR_PARAM);
|
|
68
58
|
}
|
|
59
|
+
// Get user instance
|
|
60
|
+
const p = param as IUser;
|
|
61
|
+
return new_(p.name, p.email, p.role, p.pwdHash, p.id);
|
|
62
|
+
}
|
|
69
63
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
64
|
+
/**
|
|
65
|
+
* See if the param meets criteria to be a user.
|
|
66
|
+
*/
|
|
67
|
+
function isUser(arg: unknown): boolean {
|
|
68
|
+
return (
|
|
69
|
+
!!arg &&
|
|
70
|
+
typeof arg === 'object' &&
|
|
71
|
+
'id' in arg &&
|
|
72
|
+
'email' in arg &&
|
|
73
|
+
'name' in arg &&
|
|
74
|
+
'role' in arg
|
|
75
|
+
);
|
|
83
76
|
}
|
|
84
77
|
|
|
85
78
|
|
|
86
79
|
// **** Export default **** //
|
|
87
80
|
|
|
88
|
-
export default
|
|
81
|
+
export default {
|
|
82
|
+
new: new_,
|
|
83
|
+
from,
|
|
84
|
+
isUser,
|
|
85
|
+
} as const;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"users":[{"name":"Sean Maxwell","email":"sean.maxwell@gmail.com","pwdHash":"$2b$12$1mE2OI9hMS/rgH9Mi0s85OM2V5gzm7aF3gJIWH1y0S1MqVBueyjsy","role":1,"id":159123164363},{"name":"Gordan Freeman","email":"gordan.freeman@halflife.com","pwdHash":"$2b$12$1mE2OI9hMS/rgH9Mi0s85OM2V5gzm7aF3gJIWH1y0S1MqVBueyjsy","role":0,"id":906524522143},{"name":"John Smith","email":"jsmith@yahoo.com","pwdHash":"$2b$12$1mE2OI9hMS/rgH9Mi0s85OM2V5gzm7aF3gJIWH1y0S1MqVBueyjsy","role":0,"id":357437875835}]}
|
|
1
|
+
{"users":[{"name":"Sean Maxwell","email":"sean.maxwell@gmail.com","pwdHash":"$2b$12$1mE2OI9hMS/rgH9Mi0s85OM2V5gzm7aF3gJIWH1y0S1MqVBueyjsy","role":1,"id":159123164363},{"name":"Gordan Freeman","email":"gordan.freeman@halflife.com","pwdHash":"$2b$12$1mE2OI9hMS/rgH9Mi0s85OM2V5gzm7aF3gJIWH1y0S1MqVBueyjsy","role":0,"id":906524522143},{"name":"John Smith","email":"jsmith@yahoo.com","pwdHash":"$2b$12$1mE2OI9hMS/rgH9Mi0s85OM2V5gzm7aF3gJIWH1y0S1MqVBueyjsy","role":0,"id":357437875835},{"id":75800032258,"name":"asdf","email":"asdfasdf","role":0}]}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
2
|
import jetValidator from 'jet-validator';
|
|
3
3
|
|
|
4
|
-
import adminMw from './middleware/adminMw';
|
|
5
4
|
import Paths from './constants/Paths';
|
|
6
5
|
import User from '@src/models/User';
|
|
7
|
-
import AuthRoutes from './AuthRoutes';
|
|
8
6
|
import UserRoutes from './UserRoutes';
|
|
9
7
|
|
|
10
8
|
|
|
@@ -14,27 +12,6 @@ const apiRouter = Router(),
|
|
|
14
12
|
validate = jetValidator();
|
|
15
13
|
|
|
16
14
|
|
|
17
|
-
// **** Setup **** //
|
|
18
|
-
|
|
19
|
-
const authRouter = Router();
|
|
20
|
-
|
|
21
|
-
// Login user
|
|
22
|
-
authRouter.post(
|
|
23
|
-
Paths.Auth.Login,
|
|
24
|
-
validate('email', 'password'),
|
|
25
|
-
AuthRoutes.login,
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
// Logout user
|
|
29
|
-
authRouter.get(
|
|
30
|
-
Paths.Auth.Logout,
|
|
31
|
-
AuthRoutes.logout,
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
// Add AuthRouter
|
|
35
|
-
apiRouter.use(Paths.Auth.Base, authRouter);
|
|
36
|
-
|
|
37
|
-
|
|
38
15
|
// ** Add UserRouter ** //
|
|
39
16
|
|
|
40
17
|
const userRouter = Router();
|
|
@@ -67,7 +44,7 @@ userRouter.delete(
|
|
|
67
44
|
);
|
|
68
45
|
|
|
69
46
|
// Add UserRouter
|
|
70
|
-
apiRouter.use(Paths.Users.Base,
|
|
47
|
+
apiRouter.use(Paths.Users.Base, userRouter);
|
|
71
48
|
|
|
72
49
|
|
|
73
50
|
// **** Export default **** //
|
|
@@ -75,19 +75,14 @@ app.set('views', viewsDir);
|
|
|
75
75
|
const staticDir = path.join(__dirname, 'public');
|
|
76
76
|
app.use(express.static(staticDir));
|
|
77
77
|
|
|
78
|
-
// Nav to
|
|
78
|
+
// Nav to users pg by default
|
|
79
79
|
app.get('/', (_: Request, res: Response) => {
|
|
80
|
-
res.
|
|
80
|
+
return res.redirect('/users');
|
|
81
81
|
});
|
|
82
82
|
|
|
83
83
|
// Redirect to login if not logged in.
|
|
84
|
-
app.get('/users', (
|
|
85
|
-
|
|
86
|
-
if (!jwt) {
|
|
87
|
-
res.redirect('/');
|
|
88
|
-
} else {
|
|
89
|
-
res.sendFile('users.html', {root: viewsDir});
|
|
90
|
-
}
|
|
84
|
+
app.get('/users', (_: Request, res: Response) => {
|
|
85
|
+
return res.sendFile('users.html', { root: viewsDir });
|
|
91
86
|
});
|
|
92
87
|
|
|
93
88
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
src/public/
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"parser": "@typescript-eslint/parser",
|
|
3
|
+
"plugins": [
|
|
4
|
+
"@typescript-eslint"
|
|
5
|
+
],
|
|
6
|
+
"extends": [
|
|
7
|
+
"eslint:recommended",
|
|
8
|
+
"plugin:@typescript-eslint/recommended",
|
|
9
|
+
"plugin:@typescript-eslint/recommended-requiring-type-checking",
|
|
10
|
+
"plugin:node/recommended"
|
|
11
|
+
],
|
|
12
|
+
"parserOptions": {
|
|
13
|
+
"project": "./tsconfig.json"
|
|
14
|
+
},
|
|
15
|
+
"rules": {
|
|
16
|
+
"@typescript-eslint/explicit-member-accessibility": "warn",
|
|
17
|
+
"@typescript-eslint/no-misused-promises": 0,
|
|
18
|
+
"@typescript-eslint/no-floating-promises": 0,
|
|
19
|
+
"max-len": [
|
|
20
|
+
"warn",
|
|
21
|
+
{
|
|
22
|
+
"code": 80
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"comma-dangle": ["warn", "always-multiline"],
|
|
26
|
+
"no-console": 1,
|
|
27
|
+
"no-extra-boolean-cast": 0,
|
|
28
|
+
"semi": 1,
|
|
29
|
+
"indent": ["warn", 2],
|
|
30
|
+
"quotes": ["warn", "single"],
|
|
31
|
+
"node/no-process-env": 1,
|
|
32
|
+
"node/no-unsupported-features/es-syntax": [
|
|
33
|
+
"error",
|
|
34
|
+
{ "ignores" : ["modules"] }
|
|
35
|
+
],
|
|
36
|
+
"node/no-missing-import": 0,
|
|
37
|
+
"node/no-unpublished-import": 0
|
|
38
|
+
},
|
|
39
|
+
"settings": {
|
|
40
|
+
"node": {
|
|
41
|
+
"tryExtensions": [".js", ".json", ".node", ".ts"]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
## About
|
|
2
|
+
|
|
3
|
+
This project was created with [express-generator-typescript](https://github.com/seanpmaxwell/express-generator-typescript).
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Available Scripts
|
|
7
|
+
|
|
8
|
+
### `npm run dev`
|
|
9
|
+
|
|
10
|
+
Run the server in development mode.
|
|
11
|
+
|
|
12
|
+
### `npm test`
|
|
13
|
+
|
|
14
|
+
Run all unit-tests with hot-reloading.
|
|
15
|
+
|
|
16
|
+
### `npm test -- --testFile="name of test file" (i.e. --testFile=Users).`
|
|
17
|
+
|
|
18
|
+
Run a single unit-test.
|
|
19
|
+
|
|
20
|
+
### `npm run test:no-reloading`
|
|
21
|
+
|
|
22
|
+
Run all unit-tests without hot-reloading.
|
|
23
|
+
|
|
24
|
+
### `npm run lint`
|
|
25
|
+
|
|
26
|
+
Check for linting errors.
|
|
27
|
+
|
|
28
|
+
### `npm run build`
|
|
29
|
+
|
|
30
|
+
Build the project for production.
|
|
31
|
+
|
|
32
|
+
### `npm start`
|
|
33
|
+
|
|
34
|
+
Run the production build (Must be built first).
|
|
35
|
+
|
|
36
|
+
### `npm start -- --env="name of env file" (default is production).`
|
|
37
|
+
|
|
38
|
+
Run production build with a different env file.
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
## Additional Notes
|
|
42
|
+
|
|
43
|
+
- If `npm run dev` gives you issues with bcrypt on MacOS you may need to run: `npm rebuild bcrypt --build-from-source`.
|