Hozifa Elgharbawy commited on
Commit
e3af0fd
·
2 Parent(s): dd1edf0 4fc4965

Merge branch 'main' of https://github.com/Modarb-Ai-Trainer/modarb-backend

Browse files
package-lock.json CHANGED
@@ -31,6 +31,7 @@
31
  "@types/express": "^4.17.21",
32
  "nodemon": "^3.0.2",
33
  "ts-node": "^10.9.2",
 
34
  "tsconfig-paths": "^4.2.0",
35
  "typescript": "^5.3.3"
36
  }
@@ -414,6 +415,18 @@
414
  "@types/node": "*"
415
  }
416
  },
 
 
 
 
 
 
 
 
 
 
 
 
417
  "node_modules/@types/webidl-conversions": {
418
  "version": "7.0.3",
419
  "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
@@ -603,6 +616,12 @@
603
  "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
604
  "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
605
  },
 
 
 
 
 
 
606
  "node_modules/bytes": {
607
  "version": "3.1.2",
608
  "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@@ -858,6 +877,15 @@
858
  "url": "https://github.com/motdotla/dotenv?sponsor=1"
859
  }
860
  },
 
 
 
 
 
 
 
 
 
861
  "node_modules/eastasianwidth": {
862
  "version": "0.2.0",
863
  "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@@ -1431,6 +1459,18 @@
1431
  "node": ">=8"
1432
  }
1433
  },
 
 
 
 
 
 
 
 
 
 
 
 
1434
  "node_modules/is-extglob": {
1435
  "version": "2.1.1",
1436
  "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -4800,6 +4840,12 @@
4800
  "node": ">=8"
4801
  }
4802
  },
 
 
 
 
 
 
4803
  "node_modules/path-scurry": {
4804
  "version": "1.10.1",
4805
  "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz",
@@ -4965,6 +5011,23 @@
4965
  "node": ">=8.10.0"
4966
  }
4967
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4968
  "node_modules/reusify": {
4969
  "version": "1.0.4",
4970
  "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
@@ -5208,6 +5271,25 @@
5208
  "node": ">=8"
5209
  }
5210
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5211
  "node_modules/sparse-bitfield": {
5212
  "version": "3.0.3",
5213
  "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
@@ -5291,6 +5373,15 @@
5291
  "node": ">=4"
5292
  }
5293
  },
 
 
 
 
 
 
 
 
 
5294
  "node_modules/supports-color": {
5295
  "version": "5.5.0",
5296
  "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -5303,6 +5394,18 @@
5303
  "node": ">=4"
5304
  }
5305
  },
 
 
 
 
 
 
 
 
 
 
 
 
5306
  "node_modules/tar": {
5307
  "version": "6.2.0",
5308
  "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz",
@@ -5361,6 +5464,15 @@
5361
  "node": ">=12"
5362
  }
5363
  },
 
 
 
 
 
 
 
 
 
5364
  "node_modules/ts-node": {
5365
  "version": "10.9.2",
5366
  "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
@@ -5404,6 +5516,72 @@
5404
  }
5405
  }
5406
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5407
  "node_modules/tsc-alias": {
5408
  "version": "1.8.8",
5409
  "resolved": "https://registry.npmjs.org/tsc-alias/-/tsc-alias-1.8.8.tgz",
@@ -5420,6 +5598,18 @@
5420
  "tsc-alias": "dist/bin/index.js"
5421
  }
5422
  },
 
 
 
 
 
 
 
 
 
 
 
 
5423
  "node_modules/tsconfig-paths": {
5424
  "version": "4.2.0",
5425
  "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz",
@@ -5658,6 +5848,15 @@
5658
  "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
5659
  "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
5660
  },
 
 
 
 
 
 
 
 
 
5661
  "node_modules/yallist": {
5662
  "version": "4.0.0",
5663
  "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
 
31
  "@types/express": "^4.17.21",
32
  "nodemon": "^3.0.2",
33
  "ts-node": "^10.9.2",
34
+ "ts-node-dev": "^2.0.0",
35
  "tsconfig-paths": "^4.2.0",
36
  "typescript": "^5.3.3"
37
  }
 
415
  "@types/node": "*"
416
  }
417
  },
418
+ "node_modules/@types/strip-bom": {
419
+ "version": "3.0.0",
420
+ "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz",
421
+ "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==",
422
+ "dev": true
423
+ },
424
+ "node_modules/@types/strip-json-comments": {
425
+ "version": "0.0.30",
426
+ "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz",
427
+ "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==",
428
+ "dev": true
429
+ },
430
  "node_modules/@types/webidl-conversions": {
431
  "version": "7.0.3",
432
  "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
 
616
  "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
617
  "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
618
  },
619
+ "node_modules/buffer-from": {
620
+ "version": "1.1.2",
621
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
622
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
623
+ "dev": true
624
+ },
625
  "node_modules/bytes": {
626
  "version": "3.1.2",
627
  "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
 
877
  "url": "https://github.com/motdotla/dotenv?sponsor=1"
878
  }
879
  },
880
+ "node_modules/dynamic-dedupe": {
881
+ "version": "0.3.0",
882
+ "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz",
883
+ "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==",
884
+ "dev": true,
885
+ "dependencies": {
886
+ "xtend": "^4.0.0"
887
+ }
888
+ },
889
  "node_modules/eastasianwidth": {
890
  "version": "0.2.0",
891
  "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
 
1459
  "node": ">=8"
1460
  }
1461
  },
1462
+ "node_modules/is-core-module": {
1463
+ "version": "2.13.1",
1464
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
1465
+ "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
1466
+ "dev": true,
1467
+ "dependencies": {
1468
+ "hasown": "^2.0.0"
1469
+ },
1470
+ "funding": {
1471
+ "url": "https://github.com/sponsors/ljharb"
1472
+ }
1473
+ },
1474
  "node_modules/is-extglob": {
1475
  "version": "2.1.1",
1476
  "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
 
4840
  "node": ">=8"
4841
  }
4842
  },
4843
+ "node_modules/path-parse": {
4844
+ "version": "1.0.7",
4845
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
4846
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
4847
+ "dev": true
4848
+ },
4849
  "node_modules/path-scurry": {
4850
  "version": "1.10.1",
4851
  "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz",
 
5011
  "node": ">=8.10.0"
5012
  }
5013
  },
5014
+ "node_modules/resolve": {
5015
+ "version": "1.22.8",
5016
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
5017
+ "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
5018
+ "dev": true,
5019
+ "dependencies": {
5020
+ "is-core-module": "^2.13.0",
5021
+ "path-parse": "^1.0.7",
5022
+ "supports-preserve-symlinks-flag": "^1.0.0"
5023
+ },
5024
+ "bin": {
5025
+ "resolve": "bin/resolve"
5026
+ },
5027
+ "funding": {
5028
+ "url": "https://github.com/sponsors/ljharb"
5029
+ }
5030
+ },
5031
  "node_modules/reusify": {
5032
  "version": "1.0.4",
5033
  "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
 
5271
  "node": ">=8"
5272
  }
5273
  },
5274
+ "node_modules/source-map": {
5275
+ "version": "0.6.1",
5276
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
5277
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
5278
+ "dev": true,
5279
+ "engines": {
5280
+ "node": ">=0.10.0"
5281
+ }
5282
+ },
5283
+ "node_modules/source-map-support": {
5284
+ "version": "0.5.21",
5285
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
5286
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
5287
+ "dev": true,
5288
+ "dependencies": {
5289
+ "buffer-from": "^1.0.0",
5290
+ "source-map": "^0.6.0"
5291
+ }
5292
+ },
5293
  "node_modules/sparse-bitfield": {
5294
  "version": "3.0.3",
5295
  "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
 
5373
  "node": ">=4"
5374
  }
5375
  },
5376
+ "node_modules/strip-json-comments": {
5377
+ "version": "2.0.1",
5378
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
5379
+ "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
5380
+ "dev": true,
5381
+ "engines": {
5382
+ "node": ">=0.10.0"
5383
+ }
5384
+ },
5385
  "node_modules/supports-color": {
5386
  "version": "5.5.0",
5387
  "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
 
5394
  "node": ">=4"
5395
  }
5396
  },
5397
+ "node_modules/supports-preserve-symlinks-flag": {
5398
+ "version": "1.0.0",
5399
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
5400
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
5401
+ "dev": true,
5402
+ "engines": {
5403
+ "node": ">= 0.4"
5404
+ },
5405
+ "funding": {
5406
+ "url": "https://github.com/sponsors/ljharb"
5407
+ }
5408
+ },
5409
  "node_modules/tar": {
5410
  "version": "6.2.0",
5411
  "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz",
 
5464
  "node": ">=12"
5465
  }
5466
  },
5467
+ "node_modules/tree-kill": {
5468
+ "version": "1.2.2",
5469
+ "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
5470
+ "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
5471
+ "dev": true,
5472
+ "bin": {
5473
+ "tree-kill": "cli.js"
5474
+ }
5475
+ },
5476
  "node_modules/ts-node": {
5477
  "version": "10.9.2",
5478
  "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
 
5516
  }
5517
  }
5518
  },
5519
+ "node_modules/ts-node-dev": {
5520
+ "version": "2.0.0",
5521
+ "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz",
5522
+ "integrity": "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==",
5523
+ "dev": true,
5524
+ "dependencies": {
5525
+ "chokidar": "^3.5.1",
5526
+ "dynamic-dedupe": "^0.3.0",
5527
+ "minimist": "^1.2.6",
5528
+ "mkdirp": "^1.0.4",
5529
+ "resolve": "^1.0.0",
5530
+ "rimraf": "^2.6.1",
5531
+ "source-map-support": "^0.5.12",
5532
+ "tree-kill": "^1.2.2",
5533
+ "ts-node": "^10.4.0",
5534
+ "tsconfig": "^7.0.0"
5535
+ },
5536
+ "bin": {
5537
+ "ts-node-dev": "lib/bin.js",
5538
+ "tsnd": "lib/bin.js"
5539
+ },
5540
+ "engines": {
5541
+ "node": ">=0.8.0"
5542
+ },
5543
+ "peerDependencies": {
5544
+ "node-notifier": "*",
5545
+ "typescript": "*"
5546
+ },
5547
+ "peerDependenciesMeta": {
5548
+ "node-notifier": {
5549
+ "optional": true
5550
+ }
5551
+ }
5552
+ },
5553
+ "node_modules/ts-node-dev/node_modules/glob": {
5554
+ "version": "7.2.3",
5555
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
5556
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
5557
+ "dev": true,
5558
+ "dependencies": {
5559
+ "fs.realpath": "^1.0.0",
5560
+ "inflight": "^1.0.4",
5561
+ "inherits": "2",
5562
+ "minimatch": "^3.1.1",
5563
+ "once": "^1.3.0",
5564
+ "path-is-absolute": "^1.0.0"
5565
+ },
5566
+ "engines": {
5567
+ "node": "*"
5568
+ },
5569
+ "funding": {
5570
+ "url": "https://github.com/sponsors/isaacs"
5571
+ }
5572
+ },
5573
+ "node_modules/ts-node-dev/node_modules/rimraf": {
5574
+ "version": "2.7.1",
5575
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
5576
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
5577
+ "dev": true,
5578
+ "dependencies": {
5579
+ "glob": "^7.1.3"
5580
+ },
5581
+ "bin": {
5582
+ "rimraf": "bin.js"
5583
+ }
5584
+ },
5585
  "node_modules/tsc-alias": {
5586
  "version": "1.8.8",
5587
  "resolved": "https://registry.npmjs.org/tsc-alias/-/tsc-alias-1.8.8.tgz",
 
5598
  "tsc-alias": "dist/bin/index.js"
5599
  }
5600
  },
5601
+ "node_modules/tsconfig": {
5602
+ "version": "7.0.0",
5603
+ "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz",
5604
+ "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==",
5605
+ "dev": true,
5606
+ "dependencies": {
5607
+ "@types/strip-bom": "^3.0.0",
5608
+ "@types/strip-json-comments": "0.0.30",
5609
+ "strip-bom": "^3.0.0",
5610
+ "strip-json-comments": "^2.0.0"
5611
+ }
5612
+ },
5613
  "node_modules/tsconfig-paths": {
5614
  "version": "4.2.0",
5615
  "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz",
 
5848
  "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
5849
  "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
5850
  },
5851
+ "node_modules/xtend": {
5852
+ "version": "4.0.2",
5853
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
5854
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
5855
+ "dev": true,
5856
+ "engines": {
5857
+ "node": ">=0.4"
5858
+ }
5859
+ },
5860
  "node_modules/yallist": {
5861
  "version": "4.0.0",
5862
  "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
package.json CHANGED
@@ -5,7 +5,7 @@
5
  "main": "dist/index.js",
6
  "scripts": {
7
  "start": "rimraf dist && tsc && tsc-alias && node dist/index.js",
8
- "start:dev": "nodemon -r tsconfig-paths/register src/index.ts",
9
  "build": "tsc",
10
  "lint": "eslint . --ext .ts"
11
  },
@@ -15,6 +15,7 @@
15
  "@types/express": "^4.17.21",
16
  "nodemon": "^3.0.2",
17
  "ts-node": "^10.9.2",
 
18
  "tsconfig-paths": "^4.2.0",
19
  "typescript": "^5.3.3"
20
  },
 
5
  "main": "dist/index.js",
6
  "scripts": {
7
  "start": "rimraf dist && tsc && tsc-alias && node dist/index.js",
8
+ "start:dev": "ts-node-dev -r tsconfig-paths/register src/index.ts",
9
  "build": "tsc",
10
  "lint": "eslint . --ext .ts"
11
  },
 
15
  "@types/express": "^4.17.21",
16
  "nodemon": "^3.0.2",
17
  "ts-node": "^10.9.2",
18
+ "ts-node-dev": "^2.0.0",
19
  "tsconfig-paths": "^4.2.0",
20
  "typescript": "^5.3.3"
21
  },
src/common/models/user.model.ts CHANGED
@@ -1,4 +1,4 @@
1
- import mongoose from "mongoose";
2
  import bcrypt from "bcrypt";
3
  import { AuthenticatableType } from "@common/enums/authenticatable-type.enum";
4
  import { FitnessGoal } from "@common/enums/fitness-goal.enum";
@@ -93,10 +93,33 @@ const userSchema = new Schema({
93
  });
94
 
95
  userSchema.pre("save", async function (next) {
96
- this.password = await bcrypt.hash(this.password, saltrounds);
 
 
 
 
 
97
  next();
98
  });
99
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  export type UserDocument = IUser & mongoose.Document;
101
 
102
  export const User = mongoose.model<UserDocument>("users", userSchema);
 
1
+ import mongoose, { UpdateQuery } from "mongoose";
2
  import bcrypt from "bcrypt";
3
  import { AuthenticatableType } from "@common/enums/authenticatable-type.enum";
4
  import { FitnessGoal } from "@common/enums/fitness-goal.enum";
 
93
  });
94
 
95
  userSchema.pre("save", async function (next) {
96
+ if (this.isModified("password")) {
97
+ this.password = await bcrypt.hash(this.password, saltrounds);
98
+ }
99
+ if (this.isModified("email")) {
100
+ this.email = this.email.toLowerCase();
101
+ }
102
  next();
103
  });
104
 
105
+ userSchema.pre(["updateOne", "findOneAndUpdate"], async function () {
106
+ const data = this.getUpdate() as UpdateQuery<IUser>;
107
+ if (data.password) {
108
+ data.password = await bcrypt.hash(data.password, saltrounds);
109
+ }
110
+ if (data.email) {
111
+ data.email = data.email.toLowerCase();
112
+ }
113
+ });
114
+
115
+ // pre find make email case insensitive
116
+ userSchema.pre(["find", "findOne"], function () {
117
+ const query = this.getQuery();
118
+ if (query.email) {
119
+ query.email = query.email.toLowerCase();
120
+ }
121
+ });
122
+
123
  export type UserDocument = IUser & mongoose.Document;
124
 
125
  export const User = mongoose.model<UserDocument>("users", userSchema);
src/common/validations/user-register.validation.ts CHANGED
@@ -170,7 +170,7 @@ export const userRegisterKeys = {
170
  .required()
171
  .items(
172
  joi.string().valid(...Object.values(Injury))
173
- .empty().required().messages({
174
  "string.base": "please enter a valid injuries",
175
  "any.required": "injuries must be entered",
176
  "string.empty": "injuries cannot be empty",
 
170
  .required()
171
  .items(
172
  joi.string().valid(...Object.values(Injury))
173
+ .empty().optional().messages({
174
  "string.base": "please enter a valid injuries",
175
  "any.required": "injuries must be entered",
176
  "string.empty": "injuries cannot be empty",
src/lib/services/crud.service.ts CHANGED
@@ -12,14 +12,26 @@ export const CrudService = <ModelDoc extends Document>(
12
  return this.model.create(data);
13
  }
14
 
15
- async update(
16
  filter: FilterQuery<ModelDoc>,
17
  data: AnyKeys<ModelDoc>
18
  ): Promise<ModelDoc> {
19
- return this.model.findOneAndUpdate(filter, data, { new: true });
 
 
20
  }
21
 
22
- async delete(filter: FilterQuery<ModelDoc>): Promise<ModelDoc> {
 
 
 
 
 
 
 
 
 
 
23
  return this.model.findOneAndDelete(filter);
24
  }
25
 
@@ -65,10 +77,16 @@ export const CrudService = <ModelDoc extends Document>(
65
  }
66
 
67
  async findOneOrFail(filter: FilterQuery<ModelDoc>): Promise<ModelDoc> {
 
68
  const document = await this.findOne(filter);
69
- if (!document) throw new HttpError(404, "No Matching Result Found.");
70
 
71
  return document;
72
  }
 
 
 
 
 
 
73
  };
74
  };
 
12
  return this.model.create(data);
13
  }
14
 
15
+ async updateOne(
16
  filter: FilterQuery<ModelDoc>,
17
  data: AnyKeys<ModelDoc>
18
  ): Promise<ModelDoc> {
19
+ await this.existsOrThrow(filter);
20
+ await this.model.updateOne(filter, data);
21
+ return this.findOneOrFail(filter);
22
  }
23
 
24
+ async updateMany(
25
+ filter: FilterQuery<ModelDoc>,
26
+ data: AnyKeys<ModelDoc>
27
+ ): Promise<ModelDoc[]> {
28
+ await this.existsOrThrow(filter);
29
+ await this.model.updateMany(filter, data);
30
+ return this.model.find(filter);
31
+ }
32
+
33
+ async deleteOne(filter: FilterQuery<ModelDoc>): Promise<ModelDoc> {
34
+ await this.existsOrThrow(filter);
35
  return this.model.findOneAndDelete(filter);
36
  }
37
 
 
77
  }
78
 
79
  async findOneOrFail(filter: FilterQuery<ModelDoc>): Promise<ModelDoc> {
80
+ await this.existsOrThrow(filter);
81
  const document = await this.findOne(filter);
 
82
 
83
  return document;
84
  }
85
+
86
+ private async existsOrThrow(filter: FilterQuery<ModelDoc>) {
87
+ if (!(await this.model.exists(filter))) {
88
+ throw new HttpError(404, "No Matching Result Found.");
89
+ }
90
+ }
91
  };
92
  };
src/middlewares/error-handler.middleware.ts ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { JsonResponse } from "@lib/responses/json-response";
2
+ import { NextFunction, Request, Response } from "express";
3
+ import { Error as MongooseError } from "mongoose";
4
+
5
+ export const errorHandlerMiddleware = (
6
+ err: MongooseError | any,
7
+ req: Request,
8
+ res: Response,
9
+ next: NextFunction
10
+ ) => {
11
+ let errorMessage = err.message;
12
+ let status = err.status || 500;
13
+ console.log("errorHandlerMiddleware -> err", err);
14
+
15
+ if (err.code === 11000) {
16
+ // Handle validation errors
17
+ const errors = [];
18
+ try {
19
+ const errorInKeys = Object.keys(err.keyValue);
20
+ errorInKeys.forEach((key) => {
21
+ errors.push(`${key} already exists`);
22
+ });
23
+ } catch (error) {
24
+ errors.push("Duplicate key error");
25
+ }
26
+ return JsonResponse.validationError(
27
+ {
28
+ errors,
29
+ },
30
+ res
31
+ );
32
+ } else if (err.code === 66) {
33
+ // Handle cast errors
34
+ status = 400;
35
+ if (err.path) {
36
+ errorMessage = `Invalid ${err.path}`;
37
+ } else {
38
+ errorMessage = "Invalid data";
39
+ }
40
+ } else if (err.code === 2) {
41
+ // Handle other mongoose errors
42
+ status = 400;
43
+ if (err.message) {
44
+ errorMessage = err.message;
45
+ } else {
46
+ errorMessage = "Invalid data";
47
+ }
48
+ }
49
+
50
+ JsonResponse.error(
51
+ {
52
+ error: errorMessage,
53
+ status,
54
+ },
55
+ res
56
+ );
57
+
58
+ console.error(err.message, err.stack);
59
+ };
src/modules/console/common/models/admin.model.ts CHANGED
@@ -1,4 +1,4 @@
1
- import mongoose from "mongoose";
2
  import bcrypt from "bcrypt";
3
  import { config } from "../../../../configs/config";
4
  import { Role } from "@common/enums/role.enum";
@@ -29,10 +29,33 @@ const AdminSchema = new Schema({
29
  });
30
 
31
  AdminSchema.pre("save", async function (next) {
32
- this.password = await bcrypt.hash(this.password, config.saltRounds);
 
 
 
 
 
33
  next();
34
  });
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  export type AdminDocument = mongoose.Document & IAdmin;
37
 
38
  export const Admin = mongoose.model<AdminDocument>("admins", AdminSchema);
 
1
+ import mongoose, { UpdateQuery } from "mongoose";
2
  import bcrypt from "bcrypt";
3
  import { config } from "../../../../configs/config";
4
  import { Role } from "@common/enums/role.enum";
 
29
  });
30
 
31
  AdminSchema.pre("save", async function (next) {
32
+ if (this.isModified("password")) {
33
+ this.password = await bcrypt.hash(this.password, saltrounds);
34
+ }
35
+ if (this.isModified("email")) {
36
+ this.email = this.email.toLowerCase();
37
+ }
38
  next();
39
  });
40
 
41
+ AdminSchema.pre(["updateOne", "findOneAndUpdate"], async function () {
42
+ const data = this.getUpdate() as UpdateQuery<IAdmin>;
43
+ if (data.password) {
44
+ data.password = await bcrypt.hash(data.password, saltrounds);
45
+ }
46
+ if (data.email) {
47
+ data.email = data.email.toLowerCase();
48
+ }
49
+ });
50
+
51
+ // pre find make email case insensitive
52
+ AdminSchema.pre(["find", "findOne"], function () {
53
+ const query = this.getQuery();
54
+ if (query.email) {
55
+ query.email = query.email.toLowerCase();
56
+ }
57
+ });
58
+
59
  export type AdminDocument = mongoose.Document & IAdmin;
60
 
61
  export const Admin = mongoose.model<AdminDocument>("admins", AdminSchema);
src/modules/console/modules/admins/controllers/admins.controller.ts CHANGED
@@ -14,7 +14,7 @@ import { serialize } from "@helpers/serialize";
14
  import { AdminSerialization } from "modules/console/common/serializers/admin.serialization";
15
 
16
  @Prefix("/console/admins")
17
- // @ControllerMiddleware(AdminGuardMiddleware({ roles: [Role.SUPER_ADMIN] }))
18
  export class AdminsController extends BaseController {
19
  private adminsService = new AdminsService();
20
 
@@ -81,7 +81,7 @@ export class AdminsController extends BaseController {
81
  };
82
 
83
  update = async (req: Request, res: Response): Promise<Response> => {
84
- const admin = await this.adminsService.update(
85
  {
86
  _id: req.params.id,
87
  },
@@ -97,7 +97,7 @@ export class AdminsController extends BaseController {
97
  };
98
 
99
  delete = async (req: Request, res: Response): Promise<Response> => {
100
- const admin = await this.adminsService.delete({
101
  _id: req.params.id,
102
  });
103
 
 
14
  import { AdminSerialization } from "modules/console/common/serializers/admin.serialization";
15
 
16
  @Prefix("/console/admins")
17
+ @ControllerMiddleware(AdminGuardMiddleware({ roles: [Role.SUPER_ADMIN] }))
18
  export class AdminsController extends BaseController {
19
  private adminsService = new AdminsService();
20
 
 
81
  };
82
 
83
  update = async (req: Request, res: Response): Promise<Response> => {
84
+ const admin = await this.adminsService.updateOne(
85
  {
86
  _id: req.params.id,
87
  },
 
97
  };
98
 
99
  delete = async (req: Request, res: Response): Promise<Response> => {
100
+ const admin = await this.adminsService.deleteOne({
101
  _id: req.params.id,
102
  });
103
 
src/modules/console/modules/auth/services/auth.service.ts CHANGED
@@ -7,12 +7,13 @@ import { JwtHelper } from "@helpers/jwt.helper";
7
 
8
  export class ConsoleAuthService extends CrudService(Admin) {
9
  async login(loginRequest: ILogin) {
10
- const admin = await this.findOneOrFail({ email: loginRequest.email });
 
11
  const isPasswordCorrect = await bcrypt.compare(
12
  loginRequest.password,
13
  admin.password
14
  );
15
- if (!isPasswordCorrect) throw new HttpError(401, "Incorrect Password");
16
  const token = JwtHelper.generateToken({
17
  id: admin._id,
18
  email: admin.email,
 
7
 
8
  export class ConsoleAuthService extends CrudService(Admin) {
9
  async login(loginRequest: ILogin) {
10
+ const admin = await this.findOne({ email: loginRequest.email });
11
+ if (!admin) throw new HttpError(401, "Invalid Credentials");
12
  const isPasswordCorrect = await bcrypt.compare(
13
  loginRequest.password,
14
  admin.password
15
  );
16
+ if (!isPasswordCorrect) throw new HttpError(401, "Invalid Credentials");
17
  const token = JwtHelper.generateToken({
18
  id: admin._id,
19
  email: admin.email,
src/modules/console/modules/workouts/controllers/workouts.controller.ts CHANGED
@@ -14,8 +14,7 @@ import { ControllerMiddleware } from "@lib/decorators/controller-middleware.deco
14
  import { AdminGuardMiddleware } from "modules/console/common/guards/admins.guard";
15
 
16
  @Prefix("/console/workouts")
17
- // @ControllerMiddleware(AdminGuardMiddleware())
18
-
19
  export class WorkoutController extends BaseController {
20
  private workoutsService = new WorkoutService();
21
 
@@ -78,7 +77,7 @@ export class WorkoutController extends BaseController {
78
  };
79
 
80
  update = async (req: Request, res: Response) => {
81
- const data = await this.workoutsService.update(
82
  { _id: req.params.id },
83
  req.body
84
  );
@@ -91,7 +90,7 @@ export class WorkoutController extends BaseController {
91
  };
92
 
93
  delete = async (req: Request, res: Response) => {
94
- const data = await this.workoutsService.delete({ _id: req.params.id });
95
  return JsonResponse.success(
96
  {
97
  data: serialize(data.toJSON(), WorkoutSerialization),
 
14
  import { AdminGuardMiddleware } from "modules/console/common/guards/admins.guard";
15
 
16
  @Prefix("/console/workouts")
17
+ @ControllerMiddleware(AdminGuardMiddleware({}))
 
18
  export class WorkoutController extends BaseController {
19
  private workoutsService = new WorkoutService();
20
 
 
77
  };
78
 
79
  update = async (req: Request, res: Response) => {
80
+ const data = await this.workoutsService.updateOne(
81
  { _id: req.params.id },
82
  req.body
83
  );
 
90
  };
91
 
92
  delete = async (req: Request, res: Response) => {
93
+ const data = await this.workoutsService.deleteOne({ _id: req.params.id });
94
  return JsonResponse.success(
95
  {
96
  data: serialize(data.toJSON(), WorkoutSerialization),
src/modules/users/modules/auth/controllers/auth.controller.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { UsersAuthService } from "../services/users.service";
2
  import { loginValidationSchema } from "../validation/login.validation";
3
  import { Request, Response } from "express";
4
  import { JsonResponse } from "@lib/responses/json-response";
@@ -12,6 +11,7 @@ import { BaseController } from "@lib/controllers/controller.base";
12
  import { Prefix } from "@lib/decorators/prefix.decorator";
13
  import { serialize } from "@helpers/serialize";
14
  import { UserSerialization } from "@common/serializers/user.serialization";
 
15
 
16
  @Prefix("/users/auth")
17
  export class UsersAuthController extends BaseController {
 
 
1
  import { loginValidationSchema } from "../validation/login.validation";
2
  import { Request, Response } from "express";
3
  import { JsonResponse } from "@lib/responses/json-response";
 
11
  import { Prefix } from "@lib/decorators/prefix.decorator";
12
  import { serialize } from "@helpers/serialize";
13
  import { UserSerialization } from "@common/serializers/user.serialization";
14
+ import { UsersAuthService } from "../services/users-auth.service";
15
 
16
  @Prefix("/users/auth")
17
  export class UsersAuthController extends BaseController {
src/modules/users/modules/auth/services/users-auth.service.ts CHANGED
@@ -12,12 +12,14 @@ export class UsersAuthService extends CrudService(User) {
12
  }
13
 
14
  async login(loginRequest: ILogin) {
15
- const user = await this.findOneOrFail({ email: loginRequest.email });
 
 
16
  const isPasswordCorrect = await bcrypt.compare(
17
  loginRequest.password,
18
  user.password
19
  );
20
- if (!isPasswordCorrect) throw new HttpError(401, "Incorrect Password");
21
  const token = JwtHelper.generateToken({
22
  id: user._id,
23
  email: user.email,
 
12
  }
13
 
14
  async login(loginRequest: ILogin) {
15
+ const user = await this.findOne({ email: loginRequest.email });
16
+ if (!user) throw new HttpError(401, "Invalid Credentials");
17
+
18
  const isPasswordCorrect = await bcrypt.compare(
19
  loginRequest.password,
20
  user.password
21
  );
22
+ if (!isPasswordCorrect) throw new HttpError(401, "Invalid Credentials");
23
  const token = JwtHelper.generateToken({
24
  id: user._id,
25
  email: user.email,
src/modules/users/modules/auth/services/users.service.ts DELETED
@@ -1,29 +0,0 @@
1
- import bcrypt from "bcrypt";
2
- import { ILogin } from "../validation/login.validation";
3
- import { HttpError } from "@lib/error-handling/http-error";
4
- import { JwtHelper } from "@helpers/jwt.helper";
5
- import { User } from "@common/models/user.model";
6
- import { IUserRegister } from "@common/validations/user-register.validation";
7
- import { CrudService } from "@lib/services/crud.service";
8
-
9
- export class UsersAuthService extends CrudService(User) {
10
- async register(createParams: IUserRegister) {
11
- return this.create(createParams);
12
- }
13
-
14
- async login(loginRequest: ILogin) {
15
- const user = await this.findOneOrFail({ email: loginRequest.email });
16
- const isPasswordCorrect = await bcrypt.compare(
17
- loginRequest.password,
18
- user.password
19
- );
20
- if (!isPasswordCorrect) throw new HttpError(401, "Incorrect Password");
21
- const token = JwtHelper.generateToken({
22
- id: user._id,
23
- email: user.email,
24
- name: user.name,
25
- type: "user",
26
- });
27
- return { user, token };
28
- }
29
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/routes.ts CHANGED
@@ -5,6 +5,7 @@ import path from "path";
5
  import { BaseController } from "./lib/controllers/controller.base";
6
  import { validationErrorHandler } from "./helpers/validation.helper";
7
  import { JsonResponse } from "@lib/responses/json-response";
 
8
 
9
  /**
10
  * Sets the routes for the Express app.
@@ -54,21 +55,7 @@ const setCustomRoutes = (router: Router) => {
54
  });
55
 
56
  // Error handler
57
- router.use((err, req, res, next) => {
58
- try {
59
- err.message = JSON.parse(err.message);
60
- } catch (error) {}
61
-
62
- JsonResponse.error(
63
- {
64
- error: err.message || "Internal Server Error",
65
- status: err.status || 500,
66
- },
67
- res
68
- );
69
-
70
- console.error(err.message, err.stack);
71
- });
72
  };
73
 
74
  /* importing all controllers */
@@ -96,6 +83,7 @@ const findControllerFiles = (): string[] => {
96
  const importControllers = async (router: Router) => {
97
  const files = findControllerFiles();
98
 
 
99
  await Promise.all(
100
  files.map(async (file) => {
101
  const controllerClass = await importController(file);
@@ -106,6 +94,7 @@ const importControllers = async (router: Router) => {
106
  router.use(controller.prefix, controller.router);
107
  })
108
  );
 
109
  };
110
 
111
  /**
 
5
  import { BaseController } from "./lib/controllers/controller.base";
6
  import { validationErrorHandler } from "./helpers/validation.helper";
7
  import { JsonResponse } from "@lib/responses/json-response";
8
+ import { errorHandlerMiddleware } from "middlewares/error-handler.middleware";
9
 
10
  /**
11
  * Sets the routes for the Express app.
 
55
  });
56
 
57
  // Error handler
58
+ router.use(errorHandlerMiddleware);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  };
60
 
61
  /* importing all controllers */
 
83
  const importControllers = async (router: Router) => {
84
  const files = findControllerFiles();
85
 
86
+ console.log("importing controllers...");
87
  await Promise.all(
88
  files.map(async (file) => {
89
  const controllerClass = await importController(file);
 
94
  router.use(controller.prefix, controller.router);
95
  })
96
  );
97
+ console.log("controllers imported!");
98
  };
99
 
100
  /**