express-generator-typescript 2.7.8 → 2.7.9
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/lib/project-files/README.md +65 -0
- package/lib/project-files/config/.env.development +15 -0
- package/lib/project-files/config/.env.production +15 -0
- package/lib/project-files/config/.env.test +14 -0
- package/lib/project-files/config.ts +22 -0
- package/lib/project-files/eslint.config.ts +100 -0
- package/lib/project-files/gitignore +6 -0
- package/lib/project-files/package.json +56 -0
- package/lib/project-files/scripts/build.ts +28 -0
- package/lib/project-files/scripts/common/utils.ts +93 -0
- package/lib/project-files/src/common/constants/ENV.ts +19 -0
- package/lib/project-files/src/common/constants/HTTP_STATUS_CODES.ts +81 -0
- package/lib/project-files/src/common/constants/PATHS.ts +15 -0
- package/lib/project-files/src/common/constants/index.ts +11 -0
- package/lib/project-files/src/common/util/misc.ts +11 -0
- package/lib/project-files/src/common/util/route-errors.ts +38 -0
- package/lib/project-files/src/common/util/validators.ts +14 -0
- package/lib/project-files/src/index.ts +27 -0
- package/lib/project-files/src/models/User.ts +68 -0
- package/lib/project-files/src/models/common/types.ts +5 -0
- package/lib/project-files/src/public/stylesheets/users.css +48 -0
- package/lib/project-files/src/repos/MockOrm.ts +63 -0
- package/lib/project-files/src/repos/UserRepo.ts +134 -0
- package/lib/project-files/src/repos/database.json +1 -0
- package/lib/project-files/src/repos/database.test.json +1 -0
- package/lib/project-files/src/routes/UserRoutes.ts +69 -0
- package/lib/project-files/src/routes/common/types/index.ts +10 -0
- package/lib/project-files/src/routes/common/util/index.ts +16 -0
- package/lib/project-files/src/routes/index.ts +31 -0
- package/lib/project-files/src/server.ts +86 -0
- package/lib/project-files/src/services/UserService.ts +70 -0
- package/lib/project-files/src/views/users.html +132 -0
- package/lib/project-files/tests/aux/setup.ts +26 -0
- package/lib/project-files/tests/common/types.ts +16 -0
- package/lib/project-files/tests/common/utils.ts +55 -0
- package/lib/project-files/tests/users.test.ts +133 -0
- package/lib/project-files/tsconfig.json +35 -0
- package/lib/project-files/tsconfig.prod.json +30 -0
- package/lib/project-files/vitest.config.mts +18 -0
- package/package.json +1 -1
- package/README-git +0 -78
- package/express-typescript.png +0 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { isString, isUnsignedInteger } from 'jet-validators';
|
|
2
|
+
import { parseObject, TParseOnError } from 'jet-validators/utils';
|
|
3
|
+
|
|
4
|
+
import { transformIsDate } from '@src/common/util/validators';
|
|
5
|
+
import { IModel } from './common/types';
|
|
6
|
+
|
|
7
|
+
/******************************************************************************
|
|
8
|
+
Constants
|
|
9
|
+
******************************************************************************/
|
|
10
|
+
|
|
11
|
+
const DEFAULT_USER_VALS: IUser = {
|
|
12
|
+
id: 0,
|
|
13
|
+
name: '',
|
|
14
|
+
created: new Date(),
|
|
15
|
+
email: '',
|
|
16
|
+
} as const;
|
|
17
|
+
|
|
18
|
+
/******************************************************************************
|
|
19
|
+
Types
|
|
20
|
+
******************************************************************************/
|
|
21
|
+
|
|
22
|
+
export interface IUser extends IModel {
|
|
23
|
+
name: string;
|
|
24
|
+
email: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/******************************************************************************
|
|
28
|
+
Setup
|
|
29
|
+
******************************************************************************/
|
|
30
|
+
|
|
31
|
+
// Initialize the "parseUser" function
|
|
32
|
+
const parseUser = parseObject<IUser>({
|
|
33
|
+
id: isUnsignedInteger,
|
|
34
|
+
name: isString,
|
|
35
|
+
email: isString,
|
|
36
|
+
created: transformIsDate,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
/******************************************************************************
|
|
40
|
+
Functions
|
|
41
|
+
******************************************************************************/
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* New user object.
|
|
45
|
+
*/
|
|
46
|
+
function __new__(user?: Partial<IUser>): IUser {
|
|
47
|
+
const defaults = { ...DEFAULT_USER_VALS };
|
|
48
|
+
defaults.created = new Date();
|
|
49
|
+
return parseUser({ ...defaults, ...user }, errors => {
|
|
50
|
+
throw new Error('Setup new user failed ' + JSON.stringify(errors, null, 2));
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Check is a user object. For the route validation.
|
|
56
|
+
*/
|
|
57
|
+
function test(arg: unknown, errCb?: TParseOnError): arg is IUser {
|
|
58
|
+
return !!parseUser(arg, errCb);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/******************************************************************************
|
|
62
|
+
Export default
|
|
63
|
+
******************************************************************************/
|
|
64
|
+
|
|
65
|
+
export default {
|
|
66
|
+
new: __new__,
|
|
67
|
+
test,
|
|
68
|
+
} as const;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
body {
|
|
2
|
+
padding: 100px;
|
|
3
|
+
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
body .users-column {
|
|
7
|
+
display: inline-block;
|
|
8
|
+
margin-right: 2em;
|
|
9
|
+
vertical-align: top;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
body .users-column .column-header {
|
|
13
|
+
padding-bottom: 5px;
|
|
14
|
+
font-weight: 700;
|
|
15
|
+
font-size: 1.2em;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
/** Add User Column **/
|
|
20
|
+
|
|
21
|
+
body .add-user-col input {
|
|
22
|
+
margin-bottom: 10px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
body .add-user-col #add-user-btn {
|
|
26
|
+
margin-top: 2px;
|
|
27
|
+
margin-bottom: 10px;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
/** Users Display Column **/
|
|
32
|
+
|
|
33
|
+
.email-edit {
|
|
34
|
+
padding-bottom: 8px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
body .users-column .user-display-ele {
|
|
38
|
+
padding-bottom: 10px;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
body .users-column .user-display-ele button {
|
|
42
|
+
margin-top: 2px;
|
|
43
|
+
margin-bottom: 10px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
body .users-column .user-display-ele .edit-view {
|
|
47
|
+
display: none;
|
|
48
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import jsonfile from 'jsonfile';
|
|
2
|
+
|
|
3
|
+
import ENV from '@src/common/constants/ENV';
|
|
4
|
+
import { NODE_ENVS } from '@src/common/constants';
|
|
5
|
+
import { IUser } from '@src/models/User';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
/******************************************************************************
|
|
9
|
+
Constants
|
|
10
|
+
******************************************************************************/
|
|
11
|
+
|
|
12
|
+
const DB_FILE_NAME = (
|
|
13
|
+
ENV.NodeEnv === NODE_ENVS.Test
|
|
14
|
+
? 'database.test.json'
|
|
15
|
+
: 'database.json'
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
/******************************************************************************
|
|
20
|
+
Types
|
|
21
|
+
******************************************************************************/
|
|
22
|
+
|
|
23
|
+
interface IDatabase {
|
|
24
|
+
users: IUser[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
/******************************************************************************
|
|
29
|
+
Functions
|
|
30
|
+
******************************************************************************/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Fetch the json from the file.
|
|
34
|
+
*/
|
|
35
|
+
function openDb(): Promise<IDatabase> {
|
|
36
|
+
return jsonfile.readFile(__dirname + '/' + DB_FILE_NAME) as
|
|
37
|
+
Promise<IDatabase>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Update the file.
|
|
42
|
+
*/
|
|
43
|
+
function saveDb(db: IDatabase): Promise<void> {
|
|
44
|
+
return jsonfile.writeFile((__dirname + '/' + DB_FILE_NAME), db);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Empty the database
|
|
49
|
+
*/
|
|
50
|
+
function cleanDb(): Promise<void> {
|
|
51
|
+
return jsonfile.writeFile((__dirname + '/' + DB_FILE_NAME), {});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
/******************************************************************************
|
|
56
|
+
Export default
|
|
57
|
+
******************************************************************************/
|
|
58
|
+
|
|
59
|
+
export default {
|
|
60
|
+
openDb,
|
|
61
|
+
saveDb,
|
|
62
|
+
cleanDb,
|
|
63
|
+
} as const;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { IUser } from '@src/models/User';
|
|
2
|
+
import { getRandomInt } from '@src/common/util/misc';
|
|
3
|
+
|
|
4
|
+
import orm from './MockOrm';
|
|
5
|
+
|
|
6
|
+
/******************************************************************************
|
|
7
|
+
Functions
|
|
8
|
+
******************************************************************************/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Get one user.
|
|
12
|
+
*/
|
|
13
|
+
async function getOne(email: string): Promise<IUser | null> {
|
|
14
|
+
const db = await orm.openDb();
|
|
15
|
+
for (const user of db.users) {
|
|
16
|
+
if (user.email === email) {
|
|
17
|
+
return user;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* See if a user with the given id exists.
|
|
25
|
+
*/
|
|
26
|
+
async function persists(id: number): Promise<boolean> {
|
|
27
|
+
const db = await orm.openDb();
|
|
28
|
+
for (const user of db.users) {
|
|
29
|
+
if (user.id === id) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get all users.
|
|
38
|
+
*/
|
|
39
|
+
async function getAll(): Promise<IUser[]> {
|
|
40
|
+
const db = await orm.openDb();
|
|
41
|
+
return db.users;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Add one user.
|
|
46
|
+
*/
|
|
47
|
+
async function add(user: IUser): Promise<void> {
|
|
48
|
+
const db = await orm.openDb();
|
|
49
|
+
user.id = getRandomInt();
|
|
50
|
+
db.users.push(user);
|
|
51
|
+
return orm.saveDb(db);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Update a user.
|
|
56
|
+
*/
|
|
57
|
+
async function update(user: IUser): Promise<void> {
|
|
58
|
+
const db = await orm.openDb();
|
|
59
|
+
for (let i = 0; i < db.users.length; i++) {
|
|
60
|
+
if (db.users[i].id === user.id) {
|
|
61
|
+
const dbUser = db.users[i];
|
|
62
|
+
db.users[i] = {
|
|
63
|
+
...dbUser,
|
|
64
|
+
name: user.name,
|
|
65
|
+
email: user.email,
|
|
66
|
+
};
|
|
67
|
+
return orm.saveDb(db);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Delete one user.
|
|
74
|
+
*/
|
|
75
|
+
async function delete_(id: number): Promise<void> {
|
|
76
|
+
const db = await orm.openDb();
|
|
77
|
+
for (let i = 0; i < db.users.length; i++) {
|
|
78
|
+
if (db.users[i].id === id) {
|
|
79
|
+
db.users.splice(i, 1);
|
|
80
|
+
return orm.saveDb(db);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
// **** Unit-Tests Only **** //
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Delete every user record.
|
|
90
|
+
*
|
|
91
|
+
* @internal
|
|
92
|
+
* Test-only helper. Do not use in production code.
|
|
93
|
+
*/
|
|
94
|
+
async function deleteAllUsers(): Promise<void> {
|
|
95
|
+
const db = await orm.openDb();
|
|
96
|
+
db.users = [];
|
|
97
|
+
return orm.saveDb(db);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Insert multiple users. Can't do multiple at once cause using a plain file
|
|
102
|
+
* for now.
|
|
103
|
+
*
|
|
104
|
+
* @internal
|
|
105
|
+
* Test-only helper. Do not use in production code.
|
|
106
|
+
*/
|
|
107
|
+
async function insertMult(
|
|
108
|
+
users: IUser[] | readonly IUser[],
|
|
109
|
+
): Promise<IUser[]> {
|
|
110
|
+
const db = await orm.openDb(),
|
|
111
|
+
usersF = [ ...users ];
|
|
112
|
+
for (const user of usersF) {
|
|
113
|
+
user.id = getRandomInt();
|
|
114
|
+
user.created = new Date();
|
|
115
|
+
}
|
|
116
|
+
db.users = [ ...db.users, ...users ];
|
|
117
|
+
await orm.saveDb(db);
|
|
118
|
+
return usersF;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/******************************************************************************
|
|
122
|
+
Export default
|
|
123
|
+
******************************************************************************/
|
|
124
|
+
|
|
125
|
+
export default {
|
|
126
|
+
getOne,
|
|
127
|
+
persists,
|
|
128
|
+
getAll,
|
|
129
|
+
add,
|
|
130
|
+
update,
|
|
131
|
+
delete: delete_,
|
|
132
|
+
deleteAllUsers,
|
|
133
|
+
insertMult,
|
|
134
|
+
} as const;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"users":[{"id":366115170645,"name":"Sean Maxwell","email":"smaxwell@example.com","created":"2024-03-22T05:14:36.252Z"},{"id":310946254456,"name":"John Smith","email":"john.smith@example.com","created":"2024-03-22T05:20:55.079Z"},{"id":143027113460,"name":"Gordan Freeman","email":"nova@prospect.com","created":"2024-03-22T05:42:18.895Z"}]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"users":[{"id":345992854447,"name":"Bill","created":"2025-12-18T02:17:25.124Z","email":"sean.maxwell@gmail.com"},{"id":321485906005,"name":"John Smith","created":"2025-12-18T02:17:25.124Z","email":"john.smith@gmail.com"},{"id":70616376029,"name":"Gordan Freeman","created":"2025-12-18T02:17:25.124Z","email":"gordan.freeman@gmail.com"}]}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { isNumber } from 'jet-validators';
|
|
2
|
+
import { transform } from 'jet-validators/utils';
|
|
3
|
+
|
|
4
|
+
import HTTP_STATUS_CODES from '@src/common/constants/HTTP_STATUS_CODES';
|
|
5
|
+
import UserService from '@src/services/UserService';
|
|
6
|
+
import User from '@src/models/User';
|
|
7
|
+
|
|
8
|
+
import { IReq, IRes } from './common/types';
|
|
9
|
+
import { parseReq } from './common/util';
|
|
10
|
+
|
|
11
|
+
/******************************************************************************
|
|
12
|
+
Constants
|
|
13
|
+
******************************************************************************/
|
|
14
|
+
|
|
15
|
+
const Validators = {
|
|
16
|
+
add: parseReq({ user: User.test }),
|
|
17
|
+
update: parseReq({ user: User.test }),
|
|
18
|
+
delete: parseReq({ id: transform(Number, isNumber) }),
|
|
19
|
+
} as const;
|
|
20
|
+
|
|
21
|
+
/******************************************************************************
|
|
22
|
+
Functions
|
|
23
|
+
******************************************************************************/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get all users.
|
|
27
|
+
*/
|
|
28
|
+
async function getAll(_: IReq, res: IRes) {
|
|
29
|
+
const users = await UserService.getAll();
|
|
30
|
+
res.status(HTTP_STATUS_CODES.Ok).json({ users });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Add one user.
|
|
35
|
+
*/
|
|
36
|
+
async function add(req: IReq, res: IRes) {
|
|
37
|
+
const { user } = Validators.add(req.body);
|
|
38
|
+
await UserService.addOne(user);
|
|
39
|
+
res.status(HTTP_STATUS_CODES.Created).end();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Update one user.
|
|
44
|
+
*/
|
|
45
|
+
async function update(req: IReq, res: IRes) {
|
|
46
|
+
const { user } = Validators.update(req.body);
|
|
47
|
+
await UserService.updateOne(user);
|
|
48
|
+
res.status(HTTP_STATUS_CODES.Ok).end();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Delete one user.
|
|
53
|
+
*/
|
|
54
|
+
async function delete_(req: IReq, res: IRes) {
|
|
55
|
+
const { id } = Validators.delete(req.params);
|
|
56
|
+
await UserService.delete(id);
|
|
57
|
+
res.status(HTTP_STATUS_CODES.Ok).end();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/******************************************************************************
|
|
61
|
+
Export default
|
|
62
|
+
******************************************************************************/
|
|
63
|
+
|
|
64
|
+
export default {
|
|
65
|
+
getAll,
|
|
66
|
+
add,
|
|
67
|
+
update,
|
|
68
|
+
delete: delete_,
|
|
69
|
+
} as const;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Response, Request } from 'express';
|
|
2
|
+
|
|
3
|
+
/******************************************************************************
|
|
4
|
+
Types
|
|
5
|
+
******************************************************************************/
|
|
6
|
+
|
|
7
|
+
type TRecord = Record<string, unknown>;
|
|
8
|
+
export type IReq = Request<TRecord, void, TRecord, TRecord>;
|
|
9
|
+
export type IRes = Response<unknown, TRecord>;
|
|
10
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { parseObject, TSchema } from 'jet-validators/utils';
|
|
2
|
+
import { ValidationError } from '@src/common/util/route-errors';
|
|
3
|
+
|
|
4
|
+
/******************************************************************************
|
|
5
|
+
Functions
|
|
6
|
+
******************************************************************************/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Throw a "ParseObjError" when "parseObject" fails. Also extract a nested
|
|
10
|
+
* "ParseObjError" and add it to the nestedErrors array.
|
|
11
|
+
*/
|
|
12
|
+
export function parseReq<U extends TSchema>(schema: U) {
|
|
13
|
+
return parseObject(schema, errors => {
|
|
14
|
+
throw new ValidationError(errors);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
|
|
3
|
+
import PATHS from '@src/common/constants/PATHS';
|
|
4
|
+
import UserRoutes from './UserRoutes';
|
|
5
|
+
|
|
6
|
+
/******************************************************************************
|
|
7
|
+
Setup
|
|
8
|
+
******************************************************************************/
|
|
9
|
+
|
|
10
|
+
const apiRouter = Router();
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
// ** Add UserRouter ** //
|
|
14
|
+
|
|
15
|
+
// Init router
|
|
16
|
+
const userRouter = Router();
|
|
17
|
+
|
|
18
|
+
// Get all users
|
|
19
|
+
userRouter.get(PATHS.Users.Get, UserRoutes.getAll);
|
|
20
|
+
userRouter.post(PATHS.Users.Add, UserRoutes.add);
|
|
21
|
+
userRouter.put(PATHS.Users.Update, UserRoutes.update);
|
|
22
|
+
userRouter.delete(PATHS.Users.Delete, UserRoutes.delete);
|
|
23
|
+
|
|
24
|
+
// Add UserRouter
|
|
25
|
+
apiRouter.use(PATHS.Users._, userRouter);
|
|
26
|
+
|
|
27
|
+
/******************************************************************************
|
|
28
|
+
Export default
|
|
29
|
+
******************************************************************************/
|
|
30
|
+
|
|
31
|
+
export default apiRouter;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import morgan from 'morgan';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import helmet from 'helmet';
|
|
4
|
+
import express, { Request, Response, NextFunction } from 'express';
|
|
5
|
+
import logger from 'jet-logger';
|
|
6
|
+
|
|
7
|
+
import BaseRouter from '@src/routes';
|
|
8
|
+
|
|
9
|
+
import Paths from '@src/common/constants/PATHS';
|
|
10
|
+
import ENV from '@src/common/constants/ENV';
|
|
11
|
+
import HTTP_STATUS_CODES, {
|
|
12
|
+
HttpStatusCodes,
|
|
13
|
+
} from '@src/common/constants/HTTP_STATUS_CODES';
|
|
14
|
+
import { RouteError } from '@src/common/util/route-errors';
|
|
15
|
+
import { NODE_ENVS } from '@src/common/constants';
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
/******************************************************************************
|
|
19
|
+
Setup
|
|
20
|
+
******************************************************************************/
|
|
21
|
+
|
|
22
|
+
const app = express();
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
// **** Middleware **** //
|
|
26
|
+
|
|
27
|
+
// Basic middleware
|
|
28
|
+
app.use(express.json());
|
|
29
|
+
app.use(express.urlencoded({extended: true}));
|
|
30
|
+
|
|
31
|
+
// Show routes called in console during development
|
|
32
|
+
if (ENV.NodeEnv === NODE_ENVS.Dev) {
|
|
33
|
+
app.use(morgan('dev'));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Security
|
|
37
|
+
if (ENV.NodeEnv === NODE_ENVS.Production) {
|
|
38
|
+
// eslint-disable-next-line n/no-process-env
|
|
39
|
+
if (!process.env.DISABLE_HELMET) {
|
|
40
|
+
app.use(helmet());
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Add APIs, must be after middleware
|
|
45
|
+
app.use(Paths._, BaseRouter);
|
|
46
|
+
|
|
47
|
+
// Add error handler
|
|
48
|
+
app.use((err: Error, _: Request, res: Response, next: NextFunction) => {
|
|
49
|
+
if (ENV.NodeEnv !== NODE_ENVS.Test.valueOf()) {
|
|
50
|
+
logger.err(err, true);
|
|
51
|
+
}
|
|
52
|
+
let status: HttpStatusCodes = HTTP_STATUS_CODES.BadRequest;
|
|
53
|
+
if (err instanceof RouteError) {
|
|
54
|
+
status = err.status;
|
|
55
|
+
res.status(status).json({ error: err.message });
|
|
56
|
+
}
|
|
57
|
+
return next(err);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
// **** FrontEnd Content **** //
|
|
62
|
+
|
|
63
|
+
// Set views directory (html)
|
|
64
|
+
const viewsDir = path.join(__dirname, 'views');
|
|
65
|
+
app.set('views', viewsDir);
|
|
66
|
+
|
|
67
|
+
// Set static directory (js and css).
|
|
68
|
+
const staticDir = path.join(__dirname, 'public');
|
|
69
|
+
app.use(express.static(staticDir));
|
|
70
|
+
|
|
71
|
+
// Nav to users pg by default
|
|
72
|
+
app.get('/', (_: Request, res: Response) => {
|
|
73
|
+
return res.redirect('/users');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Redirect to login if not logged in.
|
|
77
|
+
app.get('/users', (_: Request, res: Response) => {
|
|
78
|
+
return res.sendFile('users.html', { root: viewsDir });
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
/******************************************************************************
|
|
83
|
+
Export default
|
|
84
|
+
******************************************************************************/
|
|
85
|
+
|
|
86
|
+
export default app;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { RouteError } from '@src/common/util/route-errors';
|
|
2
|
+
import HTTP_STATUS_CODES from '@src/common/constants/HTTP_STATUS_CODES';
|
|
3
|
+
|
|
4
|
+
import UserRepo from '@src/repos/UserRepo';
|
|
5
|
+
import { IUser } from '@src/models/User';
|
|
6
|
+
|
|
7
|
+
/******************************************************************************
|
|
8
|
+
Constants
|
|
9
|
+
******************************************************************************/
|
|
10
|
+
|
|
11
|
+
export const USER_NOT_FOUND_ERR = 'User not found';
|
|
12
|
+
|
|
13
|
+
/******************************************************************************
|
|
14
|
+
Functions
|
|
15
|
+
******************************************************************************/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get all users.
|
|
19
|
+
*/
|
|
20
|
+
function getAll(): Promise<IUser[]> {
|
|
21
|
+
return UserRepo.getAll();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Add one user.
|
|
26
|
+
*/
|
|
27
|
+
function addOne(user: IUser): Promise<void> {
|
|
28
|
+
return UserRepo.add(user);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Update one user.
|
|
33
|
+
*/
|
|
34
|
+
async function updateOne(user: IUser): Promise<void> {
|
|
35
|
+
const persists = await UserRepo.persists(user.id);
|
|
36
|
+
if (!persists) {
|
|
37
|
+
throw new RouteError(
|
|
38
|
+
HTTP_STATUS_CODES.NotFound,
|
|
39
|
+
USER_NOT_FOUND_ERR,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
// Return user
|
|
43
|
+
return UserRepo.update(user);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Delete a user by their id.
|
|
48
|
+
*/
|
|
49
|
+
async function _delete(id: number): Promise<void> {
|
|
50
|
+
const persists = await UserRepo.persists(id);
|
|
51
|
+
if (!persists) {
|
|
52
|
+
throw new RouteError(
|
|
53
|
+
HTTP_STATUS_CODES.NotFound,
|
|
54
|
+
USER_NOT_FOUND_ERR,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
// Delete user
|
|
58
|
+
return UserRepo.delete(id);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/******************************************************************************
|
|
62
|
+
Export default
|
|
63
|
+
******************************************************************************/
|
|
64
|
+
|
|
65
|
+
export default {
|
|
66
|
+
getAll,
|
|
67
|
+
addOne,
|
|
68
|
+
updateOne,
|
|
69
|
+
delete: _delete,
|
|
70
|
+
} as const;
|