youssefkatry907 commited on
Commit
a6fbb8d
·
1 Parent(s): 33997da

User registeration & login

Browse files
.env.example CHANGED
@@ -1,5 +1,5 @@
1
  PORT =
2
-
3
  LOCAL_DB_CONNECTION_STRING =
4
  DEV_DB_CONNECTION_STRING =
5
 
 
1
  PORT =
2
+ ACCESS_TOKEN_SECRET =
3
  LOCAL_DB_CONNECTION_STRING =
4
  DEV_DB_CONNECTION_STRING =
5
 
package-lock.json CHANGED
@@ -15,6 +15,8 @@
15
  "dotenv": "^16.3.1",
16
  "express": "^4.18.2",
17
  "http": "^0.0.1-security",
 
 
18
  "mongoose": "^8.0.3",
19
  "path": "^0.12.7"
20
  },
@@ -36,6 +38,19 @@
36
  "node": ">=12"
37
  }
38
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  "node_modules/@jridgewell/resolve-uri": {
40
  "version": "3.1.1",
41
  "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
@@ -102,6 +117,24 @@
102
  "sparse-bitfield": "^3.0.3"
103
  }
104
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  "node_modules/@tsconfig/node10": {
106
  "version": "1.0.9",
107
  "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
@@ -338,6 +371,11 @@
338
  "node": ">=16.20.1"
339
  }
340
  },
 
 
 
 
 
341
  "node_modules/bytes": {
342
  "version": "3.1.2",
343
  "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@@ -541,6 +579,14 @@
541
  "url": "https://github.com/motdotla/dotenv?sponsor=1"
542
  }
543
  },
 
 
 
 
 
 
 
 
544
  "node_modules/ee-first": {
545
  "version": "1.1.1",
546
  "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -1024,6 +1070,58 @@
1024
  "node": ">=0.12.0"
1025
  }
1026
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1027
  "node_modules/kareem": {
1028
  "version": "2.5.1",
1029
  "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz",
@@ -1032,6 +1130,41 @@
1032
  "node": ">=12.0.0"
1033
  }
1034
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1035
  "node_modules/lru-cache": {
1036
  "version": "6.0.0",
1037
  "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
 
15
  "dotenv": "^16.3.1",
16
  "express": "^4.18.2",
17
  "http": "^0.0.1-security",
18
+ "joi": "^17.11.0",
19
+ "jsonwebtoken": "^9.0.2",
20
  "mongoose": "^8.0.3",
21
  "path": "^0.12.7"
22
  },
 
38
  "node": ">=12"
39
  }
40
  },
41
+ "node_modules/@hapi/hoek": {
42
+ "version": "9.3.0",
43
+ "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz",
44
+ "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ=="
45
+ },
46
+ "node_modules/@hapi/topo": {
47
+ "version": "5.1.0",
48
+ "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz",
49
+ "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==",
50
+ "dependencies": {
51
+ "@hapi/hoek": "^9.0.0"
52
+ }
53
+ },
54
  "node_modules/@jridgewell/resolve-uri": {
55
  "version": "3.1.1",
56
  "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
 
117
  "sparse-bitfield": "^3.0.3"
118
  }
119
  },
120
+ "node_modules/@sideway/address": {
121
+ "version": "4.1.4",
122
+ "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
123
+ "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==",
124
+ "dependencies": {
125
+ "@hapi/hoek": "^9.0.0"
126
+ }
127
+ },
128
+ "node_modules/@sideway/formula": {
129
+ "version": "3.0.1",
130
+ "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz",
131
+ "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg=="
132
+ },
133
+ "node_modules/@sideway/pinpoint": {
134
+ "version": "2.0.0",
135
+ "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz",
136
+ "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ=="
137
+ },
138
  "node_modules/@tsconfig/node10": {
139
  "version": "1.0.9",
140
  "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
 
371
  "node": ">=16.20.1"
372
  }
373
  },
374
+ "node_modules/buffer-equal-constant-time": {
375
+ "version": "1.0.1",
376
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
377
+ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
378
+ },
379
  "node_modules/bytes": {
380
  "version": "3.1.2",
381
  "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
 
579
  "url": "https://github.com/motdotla/dotenv?sponsor=1"
580
  }
581
  },
582
+ "node_modules/ecdsa-sig-formatter": {
583
+ "version": "1.0.11",
584
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
585
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
586
+ "dependencies": {
587
+ "safe-buffer": "^5.0.1"
588
+ }
589
+ },
590
  "node_modules/ee-first": {
591
  "version": "1.1.1",
592
  "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
 
1070
  "node": ">=0.12.0"
1071
  }
1072
  },
1073
+ "node_modules/joi": {
1074
+ "version": "17.11.0",
1075
+ "resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz",
1076
+ "integrity": "sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==",
1077
+ "dependencies": {
1078
+ "@hapi/hoek": "^9.0.0",
1079
+ "@hapi/topo": "^5.0.0",
1080
+ "@sideway/address": "^4.1.3",
1081
+ "@sideway/formula": "^3.0.1",
1082
+ "@sideway/pinpoint": "^2.0.0"
1083
+ }
1084
+ },
1085
+ "node_modules/jsonwebtoken": {
1086
+ "version": "9.0.2",
1087
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
1088
+ "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
1089
+ "dependencies": {
1090
+ "jws": "^3.2.2",
1091
+ "lodash.includes": "^4.3.0",
1092
+ "lodash.isboolean": "^3.0.3",
1093
+ "lodash.isinteger": "^4.0.4",
1094
+ "lodash.isnumber": "^3.0.3",
1095
+ "lodash.isplainobject": "^4.0.6",
1096
+ "lodash.isstring": "^4.0.1",
1097
+ "lodash.once": "^4.0.0",
1098
+ "ms": "^2.1.1",
1099
+ "semver": "^7.5.4"
1100
+ },
1101
+ "engines": {
1102
+ "node": ">=12",
1103
+ "npm": ">=6"
1104
+ }
1105
+ },
1106
+ "node_modules/jwa": {
1107
+ "version": "1.4.1",
1108
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
1109
+ "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
1110
+ "dependencies": {
1111
+ "buffer-equal-constant-time": "1.0.1",
1112
+ "ecdsa-sig-formatter": "1.0.11",
1113
+ "safe-buffer": "^5.0.1"
1114
+ }
1115
+ },
1116
+ "node_modules/jws": {
1117
+ "version": "3.2.2",
1118
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
1119
+ "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
1120
+ "dependencies": {
1121
+ "jwa": "^1.4.1",
1122
+ "safe-buffer": "^5.0.1"
1123
+ }
1124
+ },
1125
  "node_modules/kareem": {
1126
  "version": "2.5.1",
1127
  "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz",
 
1130
  "node": ">=12.0.0"
1131
  }
1132
  },
1133
+ "node_modules/lodash.includes": {
1134
+ "version": "4.3.0",
1135
+ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
1136
+ "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="
1137
+ },
1138
+ "node_modules/lodash.isboolean": {
1139
+ "version": "3.0.3",
1140
+ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
1141
+ "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="
1142
+ },
1143
+ "node_modules/lodash.isinteger": {
1144
+ "version": "4.0.4",
1145
+ "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
1146
+ "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="
1147
+ },
1148
+ "node_modules/lodash.isnumber": {
1149
+ "version": "3.0.3",
1150
+ "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
1151
+ "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="
1152
+ },
1153
+ "node_modules/lodash.isplainobject": {
1154
+ "version": "4.0.6",
1155
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
1156
+ "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="
1157
+ },
1158
+ "node_modules/lodash.isstring": {
1159
+ "version": "4.0.1",
1160
+ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
1161
+ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="
1162
+ },
1163
+ "node_modules/lodash.once": {
1164
+ "version": "4.1.1",
1165
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
1166
+ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="
1167
+ },
1168
  "node_modules/lru-cache": {
1169
  "version": "6.0.0",
1170
  "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
package.json CHANGED
@@ -23,6 +23,8 @@
23
  "dotenv": "^16.3.1",
24
  "express": "^4.18.2",
25
  "http": "^0.0.1-security",
 
 
26
  "mongoose": "^8.0.3",
27
  "path": "^0.12.7"
28
  }
 
23
  "dotenv": "^16.3.1",
24
  "express": "^4.18.2",
25
  "http": "^0.0.1-security",
26
+ "joi": "^17.11.0",
27
+ "jsonwebtoken": "^9.0.2",
28
  "mongoose": "^8.0.3",
29
  "path": "^0.12.7"
30
  }
src/configs/app.ts CHANGED
@@ -4,12 +4,14 @@ import express from "express";
4
  import bodyParser from "body-parser";
5
  import cors from "cors";
6
  import path from 'path';
 
7
  import { connection as databaseConnection } from "./database";
8
 
9
  databaseConnection();
10
  export const app = express();
11
  app.use(cors());
12
  app.use(express.json());
 
13
  app.use(bodyParser.json());
14
 
15
  app.use(bodyParser.urlencoded({ extended: false }));
 
4
  import bodyParser from "body-parser";
5
  import cors from "cors";
6
  import path from 'path';
7
+ import { routes } from "../index.route";
8
  import { connection as databaseConnection } from "./database";
9
 
10
  databaseConnection();
11
  export const app = express();
12
  app.use(cors());
13
  app.use(express.json());
14
+ app.use(routes);
15
  app.use(bodyParser.json());
16
 
17
  app.use(bodyParser.urlencoded({ extended: false }));
src/helpers/jwt.helper.ts ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import jwt from "jsonwebtoken";
2
+
3
+ export class jwtHelper {
4
+ static generateToken(payload: any) {
5
+ return jwt.sign(payload, process.env.ACCESS_TOKEN_SECRET || "secret", { expiresIn: '30d' })
6
+ }
7
+
8
+ static verifyToken(role: any) {
9
+ return (req: any, res: any, next: any) => {
10
+ let authHeader = req.headers['authorization']
11
+ const token = authHeader && authHeader.split(" ")[1]
12
+ if (token) {
13
+ jwt.verify(token, process.env.ACCESS_TOKEN_SECRET || "secret", (err: any, tokenData: any) => {
14
+ if (err) return res.status(403).json({ success: false, code: 403, message: "Invalid Token!" })
15
+ if (!role.includes(tokenData.role)) return res.status(401).json({ success: false, code: 401, message: "Unauthorized" })
16
+ req.tokenData = tokenData;
17
+ next();
18
+ })
19
+
20
+ } else return res.status(401).json({ success: false, code: 401, message: "Unauthorized" })
21
+ }
22
+ }
23
+ }
src/helpers/validation.helper.ts ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export const validator = (schema: any) => {
2
+ return (req: any, res: any, next: any) => {
3
+ try {
4
+ let validationResult = schema.body.validate(req.body);
5
+ var validation = [];
6
+ if (validationResult.error) {
7
+ validation.push(validationResult.error.details[0].message);
8
+ }
9
+ if (validation.length) {
10
+ return res.status(400).json({ success: false, error: validation.join(), code: 400 });
11
+ }
12
+ next();
13
+ } catch (err) {
14
+ console.log(`err`, err);
15
+ return res.status(400).json({ success: false, error: "Bad Request!", code: 400 });
16
+ }
17
+ };
18
+ };
src/index.route.ts ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import express from 'express';
2
+ const app = express.Router();
3
+
4
+ import { userRoutes } from './modules/user/index.route';
5
+ import { adminRoutes } from './modules/console/index.route';
6
+
7
+ app.use("/api/v1/user", userRoutes);
8
+ app.use("/api/v1/admin", adminRoutes);
9
+
10
+
11
+ app.get("/", (req: any, res: any) => {
12
+ res.status(200).json({ success: true, message: 'Welcome Message', code: 200 })
13
+ })
14
+
15
+ app.get("*", (req: any, res: any) => {
16
+ res.status(404).json({ success: false, message: "Invalid URL!", code: 404 })
17
+ })
18
+
19
+ app.post("*", (req: any, res: any) => {
20
+ res.status(404).json({ success: false, message: "Invalid URL!", code: 404 })
21
+ })
22
+
23
+ app.put("*", (req: any, res: any) => {
24
+ res.status(404).json({ success: false, message: "Invalid URL!", code: 404 })
25
+ })
26
+
27
+ app.delete("*", (req: any, res: any) => {
28
+ res.status(404).json({ success: false, message: "Invalid URL!", code: 404 })
29
+ })
30
+
31
+
32
+ app.patch("*", (req: any, res: any) => {
33
+ res.status(404).json({ success: false, message: "Invalid URL!", code: 404 })
34
+ })
35
+
36
+
37
+
38
+ export { app as routes };
src/index.ts CHANGED
@@ -1,4 +1,3 @@
1
-
2
  import { app } from "./configs/app"
3
  import http from 'http';
4
 
 
 
1
  import { app } from "./configs/app"
2
  import http from 'http';
3
 
src/modules/common/User/models/user.model.ts CHANGED
@@ -2,54 +2,57 @@ import mongoose from "mongoose";
2
  import bcrypt from "bcrypt";
3
  export const saltrounds = 5;
4
  const { Schema } = mongoose;
 
 
 
5
  enum Gender {
6
- MALE= "male",
7
- FEMALE= "female"
8
  }
9
  enum FitnessLevel {
10
- BEGINNER= "beginner",
11
- INTERMEDIATE= "intermediate",
12
- ADVANCED= "advanced"
13
  }
14
  enum FitnessGoal {
15
- LOSE_WEIGHT= "lose weight",
16
- GAIN_MUSCLE= "gain muscle",
17
- GET_FITTER= "get fitter"
18
  }
19
  enum WorkoutPlace {
20
- GYM= "gym",
21
- HOME= "home",
22
- BOTH= "both"
23
  }
24
  enum PreferredDay {
25
- SATURDAY= "saturday",
26
- SUNDAY= "sunday",
27
- MONDAY= "monday",
28
- TUESDAY= "tuesday",
29
- WEDNESDAY= "wednesday",
30
- THURSDAY= "thursday",
31
- FRIDAY= "friday"
32
  }
33
  enum PreferredEquipment {
34
- BARBELLS= "barbells",
35
- DUMBBELLS= "dumbbells",
36
- GYM_MACHINES= "gym machines",
37
- RESISTANCE_BAND= "resistance band",
38
- BODYWEIGHT= "bodyweight"
39
  }
40
  enum Injurie {
41
- NECK= "neck",
42
- SHOULDERS= "shoulders",
43
- BACK= "back",
44
- ARMS= "arms",
45
- KNEES= "knees"
46
  }
47
 
48
  const userSchema = new Schema({
49
  name: { type: String, required: true },
50
  email: { type: String, required: true, unique: true, dropDups: true },
51
  password: { type: String, required: true },
52
- image: { type: String },
53
  gender: {
54
  type: String,
55
  enum: Gender,
@@ -91,7 +94,12 @@ const userSchema = new Schema({
91
  enum: Injurie,
92
  required: true
93
  }],
94
- dob: { type: Date }
 
 
 
 
 
95
  });
96
 
97
  userSchema.pre("save", async function (next) {
 
2
  import bcrypt from "bcrypt";
3
  export const saltrounds = 5;
4
  const { Schema } = mongoose;
5
+ enum Role {
6
+ USER = "user"
7
+ }
8
  enum Gender {
9
+ MALE = "male",
10
+ FEMALE = "female"
11
  }
12
  enum FitnessLevel {
13
+ BEGINNER = "beginner",
14
+ INTERMEDIATE = "intermediate",
15
+ ADVANCED = "advanced"
16
  }
17
  enum FitnessGoal {
18
+ LOSE_WEIGHT = "lose weight",
19
+ GAIN_MUSCLE = "gain muscle",
20
+ GET_FITTER = "get fitter"
21
  }
22
  enum WorkoutPlace {
23
+ GYM = "gym",
24
+ HOME = "home",
25
+ BOTH = "both"
26
  }
27
  enum PreferredDay {
28
+ SATURDAY = "saturday",
29
+ SUNDAY = "sunday",
30
+ MONDAY = "monday",
31
+ TUESDAY = "tuesday",
32
+ WEDNESDAY = "wednesday",
33
+ THURSDAY = "thursday",
34
+ FRIDAY = "friday"
35
  }
36
  enum PreferredEquipment {
37
+ BARBELLS = "barbells",
38
+ DUMBBELLS = "dumbbells",
39
+ GYM_MACHINES = "gym machines",
40
+ RESISTANCE_BAND = "resistance band",
41
+ BODYWEIGHT = "bodyweight"
42
  }
43
  enum Injurie {
44
+ NECK = "neck",
45
+ SHOULDERS = "shoulders",
46
+ BACK = "back",
47
+ ARMS = "arms",
48
+ KNEES = "knees"
49
  }
50
 
51
  const userSchema = new Schema({
52
  name: { type: String, required: true },
53
  email: { type: String, required: true, unique: true, dropDups: true },
54
  password: { type: String, required: true },
55
+ image: { type: Object },
56
  gender: {
57
  type: String,
58
  enum: Gender,
 
94
  enum: Injurie,
95
  required: true
96
  }],
97
+ dob: { type: Date },
98
+ role: {
99
+ type: String,
100
+ enum: Role,
101
+ required: true
102
+ }
103
  });
104
 
105
  userSchema.pre("save", async function (next) {
src/modules/common/User/services/user.base.service.ts CHANGED
@@ -16,18 +16,43 @@ export class UserBaseService {
16
  return {
17
  success: true,
18
  code: 200,
19
- result: resultObject,
20
  };
21
  } catch (err) {
22
  console.log(`err.message`, err.message);
23
  return {
24
  success: false,
25
  code: 500,
26
- error: "Unexpected Error Happened.",
27
  };
28
  }
29
  }
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  static async get(filterObject) {
32
  try {
33
  const resultObject = await userModel.findOne(filterObject).lean().select("-password");
@@ -40,14 +65,14 @@ export class UserBaseService {
40
  return {
41
  success: true,
42
  code: 200,
43
- result: resultObject,
44
  };
45
  } catch (err) {
46
  console.log(`err.message`, err.message);
47
  return {
48
  success: false,
49
  code: 500,
50
- error: "Unexpected Error Happened.",
51
  };
52
  }
53
  }
@@ -69,7 +94,7 @@ export class UserBaseService {
69
  return {
70
  success: true,
71
  code: 200,
72
- result: resultArray,
73
  count,
74
  };
75
  } catch (err) {
 
16
  return {
17
  success: true,
18
  code: 200,
19
+ record: resultObject,
20
  };
21
  } catch (err) {
22
  console.log(`err.message`, err.message);
23
  return {
24
  success: false,
25
  code: 500,
26
+ error: err.message,
27
  };
28
  }
29
  }
30
 
31
+ static async create(form: { email: string }) {
32
+ try {
33
+ if (form.email) {
34
+ form.email = form.email.toLowerCase()
35
+ let user = await this.find({ email: form.email });
36
+ if (user.success) return { success: false, error: "This email already exists", code: 409 };
37
+ }
38
+
39
+ let newUser = new userModel(form);
40
+ await newUser.save();
41
+ return {
42
+ success: true,
43
+ code: 201
44
+ };
45
+
46
+ } catch (err) {
47
+ console.log(`err.message`, err.message);
48
+ return {
49
+ success: false,
50
+ code: 500,
51
+ error: err.message
52
+ };
53
+ }
54
+ }
55
+
56
  static async get(filterObject) {
57
  try {
58
  const resultObject = await userModel.findOne(filterObject).lean().select("-password");
 
65
  return {
66
  success: true,
67
  code: 200,
68
+ record: resultObject,
69
  };
70
  } catch (err) {
71
  console.log(`err.message`, err.message);
72
  return {
73
  success: false,
74
  code: 500,
75
+ error: err.message,
76
  };
77
  }
78
  }
 
94
  return {
95
  success: true,
96
  code: 200,
97
+ record: resultArray,
98
  count,
99
  };
100
  } catch (err) {
src/modules/common/User/validation/user.baseValidation.ts ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import joi from 'joi';
2
+
3
+ export class userBaseValidation {
4
+ static createValidation = {
5
+ body: joi.object().required().keys({
6
+ name: joi.string().empty().required().messages({
7
+ "string.base": "please enter a valid name",
8
+ "any.required": "name is required",
9
+ "string.empty": "name can not be empty",
10
+ }),
11
+ email: joi.string().required().email({ minDomainSegments: 2, tlds: { allow: ['com', 'net', 'org', 'eg', 'io'] } }).empty().messages({
12
+ "string.email": "please enter a valid email",
13
+ "any.required": "email must be entered",
14
+ "string.empty": "email can not be empty",
15
+ }),
16
+ password: joi.string().empty().min(8).required().messages({
17
+ "string.base": "please enter a valid password",
18
+ "any.required": "password must be entered",
19
+ "string.empty": "password cannot be empty",
20
+ "string.min": "password must be at least 8 characters"
21
+ }),
22
+ confirmPassword: joi.string().empty().min(8).required().messages({
23
+ "string.base": "please enter a valid password",
24
+ "any.required": "password must be entered",
25
+ "string.empty": "password cannot be empty",
26
+ "string.min": "password must be at least 8 characters"
27
+ }),
28
+ image: joi.object().optional().keys({
29
+ url: joi.string().optional().messages({
30
+ "string.base": "please enter a valid url",
31
+ }),
32
+ public_id: joi.string().optional().messages({
33
+ "string.base": "please enter a valid public_id",
34
+ })
35
+ }),
36
+ gender: joi.string().empty().required().messages({
37
+ "string.base": "please enter a valid gender",
38
+ "any.required": "gender must be entered",
39
+ "string.empty": "gender cannot be empty",
40
+ }),
41
+ height: joi.number().empty().required().messages({
42
+ "number.base": "please enter a valid height number",
43
+ "any.required": "height must be entered",
44
+ "number.empty": "height cannot be empty",
45
+ }),
46
+ weight: joi.number().empty().required().messages({
47
+ "number.base": "please enter a valid weight number",
48
+ "any.required": "weight must be entered",
49
+ "number.empty": "weight cannot be empty",
50
+ }),
51
+ fitness_level: joi.string().empty().required().messages({
52
+ "string.base": "please enter a valid fitness_level",
53
+ "any.required": "fitness_level must be entered",
54
+ "string.empty": "fitness_level cannot be empty",
55
+ }),
56
+ preferences: joi.object().optional().keys({
57
+ fitness_goal: joi.string().empty().required().messages({
58
+ "string.base": "please enter a valid fitness_goal",
59
+ "any.required": "fitness_goal must be entered",
60
+ "string.empty": "fitness_goal cannot be empty",
61
+ }),
62
+ target_weight: joi.number().empty().required().messages({
63
+ "number.base": "please enter a valid target_weight number",
64
+ "any.required": "target_weight must be entered",
65
+ "number.empty": "target_weight cannot be empty",
66
+ }),
67
+ workout_frequency: joi.number().empty().required().messages({
68
+ "number.base": "please enter a valid workout_frequency number",
69
+ "any.required": "workout_frequency must be entered",
70
+ "number.empty": "workout_frequency cannot be empty",
71
+ }),
72
+ preferred_days: joi.array().empty().required().items(joi.string().empty().required().messages({
73
+ "string.base": "please enter a valid preferred_days",
74
+ "any.required": "preferred_days must be entered",
75
+ "string.empty": "preferred_days cannot be empty",
76
+ })),
77
+ workout_place: joi.string().empty().required().messages({
78
+ "string.base": "please enter a valid workout_place",
79
+ "any.required": "workout_place must be entered",
80
+ "string.empty": "workout_place cannot be empty",
81
+ }),
82
+ preferred_equipment: joi.array().empty().required().items(joi.string().empty().required().messages({
83
+ "string.base": "please enter a valid preferred_equipment",
84
+ "any.required": "preferred_equipment must be entered",
85
+ "string.empty": "preferred_equipment cannot be empty",
86
+ }))
87
+ }),
88
+ injuries: joi.array().empty().required().items(joi.string().empty().required().messages({
89
+ "string.base": "please enter a valid injuries",
90
+ "any.required": "injuries must be entered",
91
+ "string.empty": "injuries cannot be empty",
92
+ })),
93
+ dob: joi.date().empty().optional().messages({
94
+ "date.base": "please enter a valid date",
95
+ })
96
+ })
97
+ }
98
+ }
src/modules/console/Admin/services/admin.service.ts CHANGED
@@ -17,7 +17,7 @@ export class AdminService {
17
  return {
18
  success: true,
19
  code: 200,
20
- result: resultObject,
21
  };
22
  } catch (err) {
23
  console.log(`err.message`, err.message);
@@ -41,7 +41,7 @@ export class AdminService {
41
  return {
42
  success: true,
43
  code: 200,
44
- result: resultObject,
45
  };
46
  } catch (err) {
47
  console.log(`err.message`, err.message);
@@ -70,7 +70,7 @@ export class AdminService {
70
  return {
71
  success: true,
72
  code: 200,
73
- result: resultArray,
74
  count,
75
  };
76
  } catch (err) {
@@ -99,7 +99,7 @@ export class AdminService {
99
  return {
100
  success: true,
101
  code: 201,
102
- result: resultObject,
103
  };
104
  } catch (err) {
105
  console.log(`err.message`, err.message);
@@ -125,7 +125,7 @@ export class AdminService {
125
  const duplicate = await this.find({ email: formObject.email });
126
  if (
127
  duplicate.success &&
128
- duplicate.result._id.toString() != existingObject.result._id.toString()
129
  )
130
  return {
131
  success: false,
@@ -173,8 +173,7 @@ export class AdminService {
173
 
174
  return {
175
  success: true,
176
- code: 200,
177
- result: "Deleted Successfully.",
178
  };
179
  } catch (err) {
180
  console.log(`err.message`, err.message);
@@ -200,7 +199,7 @@ export class AdminService {
200
 
201
  const matchingPasswords = await bcrypt.compare(
202
  passwordString,
203
- existingObject.result.password
204
  );
205
  if (!matchingPasswords)
206
  return {
@@ -211,7 +210,7 @@ export class AdminService {
211
 
212
  return {
213
  success: true,
214
- result: existingObject.result,
215
  code: 200,
216
  };
217
  } catch (err) {
 
17
  return {
18
  success: true,
19
  code: 200,
20
+ record: resultObject,
21
  };
22
  } catch (err) {
23
  console.log(`err.message`, err.message);
 
41
  return {
42
  success: true,
43
  code: 200,
44
+ record: resultObject,
45
  };
46
  } catch (err) {
47
  console.log(`err.message`, err.message);
 
70
  return {
71
  success: true,
72
  code: 200,
73
+ record: resultArray,
74
  count,
75
  };
76
  } catch (err) {
 
99
  return {
100
  success: true,
101
  code: 201,
102
+ record: resultObject,
103
  };
104
  } catch (err) {
105
  console.log(`err.message`, err.message);
 
125
  const duplicate = await this.find({ email: formObject.email });
126
  if (
127
  duplicate.success &&
128
+ duplicate.record._id.toString() != existingObject.record._id.toString()
129
  )
130
  return {
131
  success: false,
 
173
 
174
  return {
175
  success: true,
176
+ code: 200
 
177
  };
178
  } catch (err) {
179
  console.log(`err.message`, err.message);
 
199
 
200
  const matchingPasswords = await bcrypt.compare(
201
  passwordString,
202
+ existingObject.record.password
203
  );
204
  if (!matchingPasswords)
205
  return {
 
210
 
211
  return {
212
  success: true,
213
+ result: existingObject.record,
214
  code: 200,
215
  };
216
  } catch (err) {
src/modules/console/User/controllers/user.controller.ts ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { userService } from "../services/user.service";
2
+
3
+ export class adminUserController {
4
+
5
+ static async create(req, res) {
6
+ try {
7
+ let result = await userService.create(req.body);
8
+ return res.status(result.code).json(result);
9
+ } catch (err) {
10
+ console.log(`err.message`, err.message);
11
+ return res.status(500).json({
12
+ success: false,
13
+ code: 500,
14
+ error: err.message
15
+ })
16
+ }
17
+ }
18
+ }
src/modules/console/User/routes/admin.userRoute.ts ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import express from "express";
2
+ import { adminUserController } from "../controllers/user.controller";
3
+ import { adminUserValidation } from "../validation/admin.userValidation";
4
+ import { validator } from "../../../../helpers/validation.helper";
5
+
6
+ const app = express.Router();
7
+
8
+ app.post("/create", validator(adminUserValidation.createValidation), adminUserController.create);
9
+
10
+ export { app as adminUserRoutes };
11
+
src/modules/console/User/services/user.service.ts CHANGED
@@ -1,7 +1,5 @@
1
  import { UserBaseService } from "../../../common/User/services/user.base.service";
2
 
3
-
4
-
5
  export class userService extends UserBaseService {
6
 
7
  }
 
1
  import { UserBaseService } from "../../../common/User/services/user.base.service";
2
 
 
 
3
  export class userService extends UserBaseService {
4
 
5
  }
src/modules/console/User/validation/admin.userValidation.ts ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ import joi from 'joi';
2
+ import { userBaseValidation } from '../../../common/User/validation/user.baseValidation';
3
+
4
+ export class adminUserValidation extends userBaseValidation {
5
+
6
+ }
src/modules/console/index.route.ts ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import express from 'express';
2
+ const app = express();
3
+
4
+ import { jwtHelper } from '../../helpers/jwt.helper';
5
+ const allowedRoles = ["superAdmin", "admin"];
6
+
7
+ import { adminUserRoutes } from './User/routes/admin.userRoute';
8
+
9
+ app.use("/users", jwtHelper.verifyToken(allowedRoles), adminUserRoutes);
10
+
11
+ export { app as adminRoutes };
src/modules/user/User/controllers/auth.controller.ts ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { userService } from "../services/user.service";
2
+ import { jwtHelper } from "../../../../helpers/jwt.helper";
3
+
4
+ export class authController {
5
+
6
+ static async register(req, res) {
7
+ try {
8
+ let result = await userService.create(req.body);
9
+ return res.status(result.code).json(result);
10
+ } catch (err) {
11
+ console.log(`err.message`, err.message);
12
+ return res.status(500).json({
13
+ success: false,
14
+ code: 500,
15
+ error: err.message
16
+ })
17
+ }
18
+ }
19
+
20
+ static async login(req, res) {
21
+ try {
22
+ const { email, password } = req.body;
23
+ let result: { success: boolean; code: number; record?: any; message?: string } = await userService.comparePassword(email, password);
24
+ if (!result.success) return res.status(result.code).json(result);
25
+ let payload = {
26
+ _id: result.record?._id, name: result.record?.name,
27
+ email: result.record?.email,
28
+ number: result.record?.number,
29
+ role: result.record?.role
30
+ }
31
+ const token = jwtHelper.generateToken(payload);
32
+ return res.status(result.code).json({
33
+ success: result.success,
34
+ token,
35
+ code: result.code,
36
+ record: result.record
37
+ })
38
+ } catch (err) {
39
+ console.log(`err.message`, err.message);
40
+ return res.status(500).json({
41
+ success: false,
42
+ message: err.message
43
+ })
44
+ }
45
+ }
46
+ }
src/modules/user/User/routes/auth.route.ts ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import express from "express";
2
+ import { authController } from "../controllers/auth.controller";
3
+ import { userValidation } from "../validation/user.Validation";
4
+ import { validator } from "../../../../helpers/validation.helper";
5
+
6
+ const app = express.Router();
7
+
8
+ app.post("/register", validator(userValidation.createValidation), authController.register);
9
+ app.post("/login", validator(userValidation.loginValidation), authController.login);
10
+
11
+ export { app as authRoutes };
12
+
src/modules/user/User/services/user.service.ts ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { UserBaseService } from "../../../common/User/services/user.base.service";
2
+ import { userModel, } from "../../../common/User/models/user.model";
3
+ import bcrypt from "bcrypt";
4
+
5
+ export class userService extends UserBaseService {
6
+
7
+ static async comparePassword(email: string, password: string) {
8
+ try {
9
+ if (email != undefined) {
10
+ email = email.toLowerCase();
11
+ }
12
+ let result = await UserBaseService.find({ email })
13
+ if (!result.success) return result;
14
+
15
+ let match = await bcrypt.compare(password, result.record.password)
16
+ delete result.record.password;
17
+
18
+ if (!match) return {
19
+ success: false,
20
+ code: 409,
21
+ message: "password isn't correct"
22
+ }
23
+
24
+ return {
25
+ success: true,
26
+ code: 200,
27
+ record: result.record
28
+ }
29
+
30
+ } catch (err) {
31
+ console.log(`err.message`, err.message);
32
+ return {
33
+ success: false,
34
+ code: 500,
35
+ error: err.message
36
+ };
37
+ }
38
+ }
39
+
40
+ // static async resetPassword(_id: any, currentPassword: string, newPassword: string, confirmPassword: string) {
41
+ // try {
42
+ // let user = await UserBaseService.find({ _id })
43
+ // let saltrouds = 5;
44
+ // let oldPassword = user.record.password;
45
+ // let ok = await bcrypt.compare(currentPassword, oldPassword)
46
+
47
+ // if (user.success) {
48
+
49
+ // if (!ok) return {
50
+ // success: false,
51
+ // code: 409,
52
+ // message: "current password isn't correct"
53
+ // };
54
+
55
+ // if (newPassword == currentPassword) return {
56
+ // success: false,
57
+ // code: 409,
58
+ // message: "new password must be different from current password"
59
+ // };
60
+
61
+ // if (newPassword != confirmPassword) return {
62
+ // success: false,
63
+ // code: 409,
64
+ // message: "passwords don't match"
65
+ // };
66
+
67
+ // const hashedPassword = await bcrypt.hash(newPassword, saltrouds)
68
+ // await userModel.findByIdAndUpdate(_id, { password: hashedPassword })
69
+ // return {
70
+ // success: true,
71
+ // code: 200,
72
+ // message: "password changed successfully"
73
+ // };
74
+ // }
75
+ // else return {
76
+ // success: false,
77
+ // code: 404,
78
+ // error: user.error
79
+ // };
80
+ // } catch (err) {
81
+ // console.log(`err.message`, err.message);
82
+ // return {
83
+ // success: false,
84
+ // code: 500,
85
+ // error: err.message
86
+ // };
87
+ // }
88
+ // }
89
+ }
90
+
91
+
92
+
src/modules/user/User/validation/user.Validation.ts ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import joi from 'joi';
2
+ import { userBaseValidation } from '../../../common/User/validation/user.baseValidation';
3
+
4
+ export class userValidation extends userBaseValidation {
5
+ static loginValidation = {
6
+ body: joi.object().required().keys({
7
+
8
+ email: joi.string().required().email({ minDomainSegments: 2, tlds: { allow: ['com', 'net', 'org', 'eg', 'io'] } }).empty().messages({
9
+ "string.email": "please enter a valid email",
10
+ "any.required": "email must be entered",
11
+ "string.empty": "email can not be empty"
12
+ }),
13
+ password: joi.string().empty().min(8).required().messages({
14
+ "string.base": "please enter a valid password",
15
+ "any.required": "password must be entered",
16
+ "string.empty": "password cannot be empty",
17
+ "string.min": "password must be at least 8 characters"
18
+ })
19
+ })
20
+ }
21
+ }
src/modules/user/index.route.ts ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import express from 'express';
2
+ const app = express();
3
+
4
+ import { jwtHelper } from '../../helpers/jwt.helper';
5
+ const allowedRoles = ["user"];
6
+
7
+ import { authRoutes } from './User/routes/auth.route';
8
+
9
+ app.use(authRoutes);
10
+
11
+ export { app as userRoutes };