diff --git a/catalogos.sql b/catalogos.sql index d6e1d7f..97139de 100644 --- a/catalogos.sql +++ b/catalogos.sql @@ -1,8 +1,8 @@ -INSERT INTO institucion (institucion, logo) VALUES ("Facultad de Arquitectura", "url"); INSERT INTO institucion (institucion, logo) VALUES ("FES Acatlán", "url"); +INSERT INTO institucion (institucion, logo) VALUES ("Facultad de Arquitectura", "url"); -INSERT INTO carrera (carrera, id_institucion) VALUES ("Matemáticas Aplicadas y Computación", 2); -INSERT INTO carrera (carrera, id_institucion) VALUES ("Arquitectura", 1); +INSERT INTO carrera (carrera, id_institucion) VALUES ("Matemáticas Aplicadas y Computación", 1); +INSERT INTO carrera (carrera, id_institucion) VALUES ("Arquitectura", 2); INSERT INTO status (status) VALUES ("Activo"); INSERT INTO status (status) VALUES ("Apartado"); diff --git a/package-lock.json b/package-lock.json index 17a31f9..de191e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,12 +12,16 @@ "@nestjs/common": "^8.0.0", "@nestjs/config": "^2.0.0", "@nestjs/core": "^8.0.0", + "@nestjs/jwt": "^8.0.0", + "@nestjs/passport": "^8.2.1", "@nestjs/platform-express": "^8.0.0", "@nestjs/typeorm": "^8.0.3", "bcrypt": "^5.0.1", "class-transformer": "^0.5.1", "class-validator": "^0.13.2", "mysql2": "^2.3.3", + "passport": "^0.5.2", + "passport-jwt": "^4.0.0", "reflect-metadata": "^0.1.13", "rimraf": "^3.0.2", "rxjs": "^7.2.0", @@ -1490,6 +1494,27 @@ } } }, + "node_modules/@nestjs/jwt": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-8.0.0.tgz", + "integrity": "sha512-fz2LQgYY2zmuD8S+8UE215anwKyXlnB/1FwJQLVR47clNfMeFMK8WCxmn6xdPhF5JKuV1crO6FVabb1qWzDxqQ==", + "dependencies": { + "@types/jsonwebtoken": "8.5.4", + "jsonwebtoken": "8.5.1" + }, + "peerDependencies": { + "@nestjs/common": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@nestjs/passport": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-8.2.1.tgz", + "integrity": "sha512-HXEKMLX1x865+lsJB4srwKHBciDNAhWY1Ha+xbxYRbk7J5leGDoHJAmeqe+Wb3NDn5nkboggLV87t0q2mbYc8w==", + "peerDependencies": { + "@nestjs/common": "^6.0.0 || ^7.0.0 || ^8.0.0", + "passport": "^0.4.0 || ^0.5.0" + } + }, "node_modules/@nestjs/platform-express": { "version": "8.4.3", "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-8.4.3.tgz", @@ -1934,6 +1959,14 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "node_modules/@types/jsonwebtoken": { + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.4.tgz", + "integrity": "sha512-4L8msWK31oXwdtC81RmRBAULd0ShnAHjBuKT9MRQpjP0piNrZdXyTRcKY9/UIfhGeKIT4PvF5amOOUbbT/9Wpg==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -1943,8 +1976,7 @@ "node_modules/@types/node": { "version": "16.11.26", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.26.tgz", - "integrity": "sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ==", - "dev": true + "integrity": "sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ==" }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -3001,6 +3033,11 @@ "ieee754": "^1.1.13" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -3765,6 +3802,14 @@ "node": ">=12" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -6407,6 +6452,54 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=4", + "npm": ">=1.4.28" + } + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -6475,6 +6568,36 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -6487,6 +6610,11 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -7211,6 +7339,39 @@ "node": ">= 0.8" } }, + "node_modules/passport": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.5.2.tgz", + "integrity": "sha512-w9n/Ot5I7orGD4y+7V3EFJCQEznE5RxHamUxcqLT2QoJY0f2JdN8GyHonYFvN0Vz+L6lUJfVhrk2aZz2LbuREw==", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-jwt": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.0.tgz", + "integrity": "sha512-BwC0n2GP/1hMVjR4QpnvqA61TxenUMlmfNjYNgK0ZAs0HK4SOQkHcSv4L328blNTLtHq7DbmvyNJiH+bn6C5Mg==", + "dependencies": { + "jsonwebtoken": "^8.2.0", + "passport-strategy": "^1.0.0" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -7257,6 +7418,11 @@ "node": ">=8" } }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -10657,6 +10823,21 @@ "uuid": "8.3.2" } }, + "@nestjs/jwt": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-8.0.0.tgz", + "integrity": "sha512-fz2LQgYY2zmuD8S+8UE215anwKyXlnB/1FwJQLVR47clNfMeFMK8WCxmn6xdPhF5JKuV1crO6FVabb1qWzDxqQ==", + "requires": { + "@types/jsonwebtoken": "8.5.4", + "jsonwebtoken": "8.5.1" + } + }, + "@nestjs/passport": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-8.2.1.tgz", + "integrity": "sha512-HXEKMLX1x865+lsJB4srwKHBciDNAhWY1Ha+xbxYRbk7J5leGDoHJAmeqe+Wb3NDn5nkboggLV87t0q2mbYc8w==", + "requires": {} + }, "@nestjs/platform-express": { "version": "8.4.3", "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-8.4.3.tgz", @@ -11023,6 +11204,14 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "@types/jsonwebtoken": { + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.4.tgz", + "integrity": "sha512-4L8msWK31oXwdtC81RmRBAULd0ShnAHjBuKT9MRQpjP0piNrZdXyTRcKY9/UIfhGeKIT4PvF5amOOUbbT/9Wpg==", + "requires": { + "@types/node": "*" + } + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -11032,8 +11221,7 @@ "@types/node": { "version": "16.11.26", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.26.tgz", - "integrity": "sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ==", - "dev": true + "integrity": "sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ==" }, "@types/parse-json": { "version": "4.0.0", @@ -11844,6 +12032,11 @@ "ieee754": "^1.1.13" } }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -12438,6 +12631,14 @@ "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-8.0.2.tgz", "integrity": "sha512-vKKAk+VOzAWOV/dPIeSYqhgC/TQY+6L6Ibkzfsr8xd1stdBsTuGu9asCOXgbYbBeS+f2Y6lqqEuw7riOA+xEUQ==" }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -14436,6 +14637,49 @@ "universalify": "^2.0.0" } }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -14489,6 +14733,36 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -14501,6 +14775,11 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -15063,6 +15342,29 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, + "passport": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.5.2.tgz", + "integrity": "sha512-w9n/Ot5I7orGD4y+7V3EFJCQEznE5RxHamUxcqLT2QoJY0f2JdN8GyHonYFvN0Vz+L6lUJfVhrk2aZz2LbuREw==", + "requires": { + "passport-strategy": "1.x.x", + "pause": "0.0.1" + } + }, + "passport-jwt": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.0.tgz", + "integrity": "sha512-BwC0n2GP/1hMVjR4QpnvqA61TxenUMlmfNjYNgK0ZAs0HK4SOQkHcSv4L328blNTLtHq7DbmvyNJiH+bn6C5Mg==", + "requires": { + "jsonwebtoken": "^8.2.0", + "passport-strategy": "^1.0.0" + } + }, + "passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" + }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -15097,6 +15399,11 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", diff --git a/package.json b/package.json index 8fe5d87..b5eeda6 100644 --- a/package.json +++ b/package.json @@ -24,12 +24,16 @@ "@nestjs/common": "^8.0.0", "@nestjs/config": "^2.0.0", "@nestjs/core": "^8.0.0", + "@nestjs/jwt": "^8.0.0", + "@nestjs/passport": "^8.2.1", "@nestjs/platform-express": "^8.0.0", "@nestjs/typeorm": "^8.0.3", "bcrypt": "^5.0.1", "class-transformer": "^0.5.1", "class-validator": "^0.13.2", "mysql2": "^2.3.3", + "passport": "^0.5.2", + "passport-jwt": "^4.0.0", "reflect-metadata": "^0.1.13", "rimraf": "^3.0.2", "rxjs": "^7.2.0", diff --git a/src/app.module.ts b/src/app.module.ts index 1817c0e..967f586 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -45,20 +45,22 @@ import { TipoCarrito } from './institucion-tipo-carrito/entity/tipo-carrito.enti import { TipoEntrada } from './tipo-entrada/entity/tipo-entrada.entity'; import { TipoUsuario } from './tipo-usuario/entity/tipo-usuario.entity'; import { Usuario } from './usuario/entity/usuario.entity'; +import { AuthModule } from './auth/auth.module'; +import { BcryptModule } from './bcrypt/bcrypt.module'; @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true }), TypeOrmModule.forRootAsync({ inject: [ConfigService], - useFactory: (config: ConfigService) => { + useFactory: (configService: ConfigService) => { return { type: 'mariadb', - host: config.get('DB_HOST'), - database: config.get('DB'), - username: config.get('DB_USER'), - password: config.get('DB_PASSWORD'), - port: config.get('DB_PORT'), + host: configService.get('DB_HOST'), + database: configService.get('DB'), + username: configService.get('DB_USER'), + password: configService.get('DB_PASSWORD'), + port: Number(configService.get('DB_PORT')), synchronize: true, entities: [ Carrera, @@ -88,6 +90,7 @@ import { Usuario } from './usuario/entity/usuario.entity'; }; }, }), + AuthModule, CarreraModule, CarreraProgramaModule, CarritoModule, @@ -107,6 +110,7 @@ import { Usuario } from './usuario/entity/usuario.entity'; TipoUsuarioModule, UsuarioModule, InstitucionTipoCarritoModule, + BcryptModule, ], }) export class AppModule {} diff --git a/src/auth/auth.controller.spec.ts b/src/auth/auth.controller.spec.ts new file mode 100644 index 0000000..27a31e6 --- /dev/null +++ b/src/auth/auth.controller.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { AuthController } from './auth.controller'; + +describe('AuthController', () => { + let controller: AuthController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [AuthController], + }).compile(); + + controller = module.get(AuthController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts new file mode 100644 index 0000000..4ccded8 --- /dev/null +++ b/src/auth/auth.controller.ts @@ -0,0 +1,24 @@ +import { Body, Controller, Post } from '@nestjs/common'; +import { AuthService } from './auth.service'; +import { AuthLoginOperadorDto } from './dto/auth-login-operador.dto'; +import { AuthLoginUsuarioDto } from './dto/auth-login-usuario.dto'; + +@Controller('auth') +export class AuthController { + constructor(private authService: AuthService) {} + + @Post('login_operador') + loginOperador(@Body() body: AuthLoginOperadorDto) { + return this.authService.loginOperador( + Number(body.id_institucion), + Number(body.id_modulo), + body.operador, + body.password, + ); + } + + @Post('login_usuario') + loginUsuario(@Body() body: AuthLoginUsuarioDto) { + return this.authService.loginUsuario(body.usuario, body.password); + } +} diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts new file mode 100644 index 0000000..490dc37 --- /dev/null +++ b/src/auth/auth.module.ts @@ -0,0 +1,33 @@ +import { ConfigService } from '@nestjs/config'; +import { Module } from '@nestjs/common'; +import { JwtModule } from '@nestjs/jwt'; +import { PassportModule } from '@nestjs/passport'; +import { AuthController } from './auth.controller'; +import { AuthService } from './auth.service'; +import { BcryptModule } from '../bcrypt/bcrypt.module'; +import { JwtStrategyService } from './strategy/jwt-strategy.service'; +import { ModuloModule } from '../modulo/modulo.module'; +import { OperadorModule } from '../operador/operador.module'; +import { UsuarioModule } from '../usuario/usuario.module'; + +@Module({ + imports: [ + PassportModule.register({ defaultStrategy: 'jwt' }), + JwtModule.registerAsync({ + inject: [ConfigService], + useFactory: (configService: ConfigService) => { + return { + secret: configService.get('AUTH_SECRETKEY'), + signOptions: { expiresIn: '30s' }, + }; + }, + }), + BcryptModule, + ModuloModule, + OperadorModule, + UsuarioModule, + ], + controllers: [AuthController], + providers: [AuthService, JwtStrategyService], +}) +export class AuthModule {} diff --git a/src/auth/auth.service.spec.ts b/src/auth/auth.service.spec.ts new file mode 100644 index 0000000..800ab66 --- /dev/null +++ b/src/auth/auth.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { AuthService } from './auth.service'; + +describe('AuthService', () => { + let service: AuthService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [AuthService], + }).compile(); + + service = module.get(AuthService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts new file mode 100644 index 0000000..11ce4fa --- /dev/null +++ b/src/auth/auth.service.ts @@ -0,0 +1,77 @@ +import { + ConflictException, + Injectable, + UnauthorizedException, +} from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; +import { BcryptService } from '../bcrypt/bcrypt.service'; +import { ModuloService } from '../modulo/modulo.service'; +import { OperadorService } from '../operador/operador.service'; +import { UsuarioService } from '../usuario/usuario.service'; +import { JwtPayload } from './dto/jwt-payload'; + +@Injectable() +export class AuthService { + constructor( + private bcryptService: BcryptService, + private jwtService: JwtService, + private moduloService: ModuloService, + private operadorService: OperadorService, + private usuarioService: UsuarioService, + ) {} + + validate() {} + + loginUsuario(usuario: string, password: string) { + return this.usuarioService.findByUsuario(usuario).then((usuario) => { + if (!this.bcryptService.comparar(password, usuario.password)) + throw new UnauthorizedException( + 'Usuario y/o password incorrectos, trata de nuevo.', + ); + + const payload: JwtPayload = { + id_usuario: usuario.id_usuario, + id_tipo_usuario: usuario.tipoUsuario.id_tipo_usuario, + }; + + return { usuario, token: this.jwtService.sign(payload) }; + }); + } + + async loginOperador( + id_institucion: number, + id_modulo: number, + operador: string, + password: string, + ) { + const modulo = await this.moduloService.findById(id_modulo); + + return this.operadorService + .findByOperador(id_institucion, operador) + .then((operador) => { + if (!this.bcryptService.comparar(password, operador.password)) + throw new UnauthorizedException( + 'Usuario y/o password incorrectos, trata de nuevo.', + ); + if (!operador.activo) + throw new UnauthorizedException( + 'Esta cuenta se encuentra desactivada.', + ); + if ( + modulo.institucion.id_institucion != + operador.institucion.id_institucion + ) + throw new ConflictException( + 'El módulo seleccionado no pertenece a la misma institución al la que pertenece el operador.', + ); + + const payload: JwtPayload = { + id_operador: operador.id_operador, + id_tipo_usuario: operador.tipoUsuario.id_tipo_usuario, + id_modulo: modulo.id_modulo, + }; + + return { operador, token: this.jwtService.sign(payload) }; + }); + } +} diff --git a/src/auth/dto/auth-login-operador.dto.ts b/src/auth/dto/auth-login-operador.dto.ts new file mode 100644 index 0000000..7f523d0 --- /dev/null +++ b/src/auth/dto/auth-login-operador.dto.ts @@ -0,0 +1,15 @@ +import { IsInt, IsString } from 'class-validator'; + +export class AuthLoginOperadorDto { + @IsInt() + id_institucion: string; + + @IsInt() + id_modulo: string; + + @IsString() + operador: string; + + @IsString() + password: string; +} diff --git a/src/usuario/dto/usuario-login.dto.ts b/src/auth/dto/auth-login-usuario.dto.ts similarity index 79% rename from src/usuario/dto/usuario-login.dto.ts rename to src/auth/dto/auth-login-usuario.dto.ts index 2168ad1..cdaaeea 100644 --- a/src/usuario/dto/usuario-login.dto.ts +++ b/src/auth/dto/auth-login-usuario.dto.ts @@ -1,6 +1,6 @@ import { IsNumberString, IsString } from 'class-validator'; -export class UsuarioLoginDto { +export class AuthLoginUsuarioDto { @IsNumberString() usuario: string; diff --git a/src/auth/dto/jwt-payload.ts b/src/auth/dto/jwt-payload.ts new file mode 100644 index 0000000..3a1aaca --- /dev/null +++ b/src/auth/dto/jwt-payload.ts @@ -0,0 +1,9 @@ +export class JwtPayload { + id_tipo_usuario: number; + + id_usuario?: number; + + id_operador?: number; + + id_modulo?: number; +} diff --git a/src/auth/strategy/jwt-strategy.service.ts b/src/auth/strategy/jwt-strategy.service.ts new file mode 100644 index 0000000..df90c43 --- /dev/null +++ b/src/auth/strategy/jwt-strategy.service.ts @@ -0,0 +1,20 @@ +import { Injectable } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { PassportStrategy } from '@nestjs/passport'; +import { Strategy, ExtractJwt } from 'passport-jwt'; +import { JwtPayload } from '../dto/jwt-payload'; + +@Injectable() +export class JwtStrategyService extends PassportStrategy(Strategy) { + constructor(private configService: ConfigService) { + super({ + jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), + secretOrKey: configService.get('AUTH_SECRETKEY'), + }); + } + + validate(payload: JwtPayload) { + console.log(payload); + return true; + } +} diff --git a/src/bcrypt/bcrypt.module.ts b/src/bcrypt/bcrypt.module.ts new file mode 100644 index 0000000..937f55c --- /dev/null +++ b/src/bcrypt/bcrypt.module.ts @@ -0,0 +1,8 @@ +import { Module } from '@nestjs/common'; +import { BcryptService } from './bcrypt.service'; + +@Module({ + providers: [BcryptService], + exports: [BcryptService], +}) +export class BcryptModule {} diff --git a/src/bcrypt/bcrypt.service.spec.ts b/src/bcrypt/bcrypt.service.spec.ts new file mode 100644 index 0000000..07edb14 --- /dev/null +++ b/src/bcrypt/bcrypt.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { BcryptService } from './bcrypt.service'; + +describe('BcryptService', () => { + let service: BcryptService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [BcryptService], + }).compile(); + + service = module.get(BcryptService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/bcrypt/bcrypt.service.ts b/src/bcrypt/bcrypt.service.ts new file mode 100644 index 0000000..8b487f8 --- /dev/null +++ b/src/bcrypt/bcrypt.service.ts @@ -0,0 +1,20 @@ +import { Injectable } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import * as bcrypt from 'bcrypt'; + +@Injectable() +export class BcryptService { + constructor(private configService: ConfigService) {} + + encriptar(password: string) { + const salt = bcrypt.genSaltSync( + Number(this.configService.get('SALT_ROUNDS')), + ); + + return bcrypt.hashSync(password, salt); + } + + comparar(password: string, passwordDb: string) { + return bcrypt.compareSync(password, passwordDb); + } +} diff --git a/src/carrera/carrera.module.ts b/src/carrera/carrera.module.ts index 9108d26..5707bd3 100644 --- a/src/carrera/carrera.module.ts +++ b/src/carrera/carrera.module.ts @@ -8,5 +8,6 @@ import { Carrera } from './entity/carrera.entity'; imports: [TypeOrmModule.forFeature([Carrera])], controllers: [CarreraController], providers: [CarreraService], + exports: [CarreraService], }) export class CarreraModule {} diff --git a/src/modulo/modulo.module.ts b/src/modulo/modulo.module.ts index 868ee0f..3406016 100644 --- a/src/modulo/modulo.module.ts +++ b/src/modulo/modulo.module.ts @@ -9,5 +9,6 @@ import { InstitucionModule } from '../institucion/institucion.module'; imports: [TypeOrmModule.forFeature([Modulo]), InstitucionModule], controllers: [ModuloController], providers: [ModuloService], + exports: [ModuloService], }) export class ModuloModule {} diff --git a/src/modulo/modulo.service.ts b/src/modulo/modulo.service.ts index 1071813..7761798 100644 --- a/src/modulo/modulo.service.ts +++ b/src/modulo/modulo.service.ts @@ -51,16 +51,21 @@ export class ModuloService { }); } - async update(attrs: Partial) { - const modulo = await this.findById(attrs.id_modulo); - - return this.repository - .findOne({ modulo: attrs.modulo, institucion: modulo.institucion }) - .then((existeModulo) => { - if (existeModulo) - throw new ConflictException( - 'Ya existe un módulo con este nombre, intente con otro nombre.', - ); + update(attrs: Partial) { + return this.findById(attrs.id_modulo) + .then(async (modulo) => { + if (attrs.modulo) + await this.repository + .findOne({ + modulo: attrs.modulo, + institucion: modulo.institucion, + }) + .then((existeModulo) => { + if (existeModulo) + throw new ConflictException( + 'Ya existe un módulo con este nombre, intente con otro nombre.', + ); + }); Object.assign(modulo, attrs); return this.repository.save(modulo); }) diff --git a/src/operador/dto/operador-login.dto.ts b/src/operador/dto/operador-login.dto.ts deleted file mode 100644 index 9cc20e3..0000000 --- a/src/operador/dto/operador-login.dto.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { IsNumberString, IsString } from 'class-validator'; - -export class OperadorLoginDto { - @IsNumberString() - operador: string; - - @IsString() - password: string; -} diff --git a/src/operador/dto/operador-update.dto.ts b/src/operador/dto/operador-update.dto.ts index a8fad9a..f979fdb 100644 --- a/src/operador/dto/operador-update.dto.ts +++ b/src/operador/dto/operador-update.dto.ts @@ -8,9 +8,9 @@ export class OperadorUpdateDto { @IsOptional() activo?: boolean; - @IsString() - @IsOptional() - operador?: string; + // @IsString() + // @IsOptional() + // operador?: string; @IsString() @IsOptional() diff --git a/src/operador/dto/operador.dto.ts b/src/operador/dto/operador.dto.ts index eebc66e..872d995 100644 --- a/src/operador/dto/operador.dto.ts +++ b/src/operador/dto/operador.dto.ts @@ -1,6 +1,6 @@ -import { IsString } from 'class-validator'; +import { IsNumberString } from 'class-validator'; export class OperadorDto { - @IsString() - operador: string; + @IsNumberString() + id_operador: string; } diff --git a/src/operador/entity/operador.entity.ts b/src/operador/entity/operador.entity.ts index e6f2af0..969f469 100644 --- a/src/operador/entity/operador.entity.ts +++ b/src/operador/entity/operador.entity.ts @@ -25,11 +25,15 @@ export class Operador { @Column({ type: String, nullable: false, length: 60 }) password: string; - @ManyToOne(() => Institucion, (institucion) => institucion.operadores) + @ManyToOne(() => Institucion, (institucion) => institucion.operadores, { + eager: true, + }) @JoinColumn({ name: 'id_institucion' }) institucion: Institucion; - @ManyToOne(() => TipoUsuario, (tipoUsuario) => tipoUsuario.operadores) + @ManyToOne(() => TipoUsuario, (tipoUsuario) => tipoUsuario.operadores, { + eager: true, + }) @JoinColumn({ name: 'id_tipo_usuario' }) tipoUsuario: TipoUsuario; diff --git a/src/operador/operador.controller.ts b/src/operador/operador.controller.ts index faf7ac6..9fec5e1 100644 --- a/src/operador/operador.controller.ts +++ b/src/operador/operador.controller.ts @@ -1,7 +1,6 @@ import { Body, Controller, Get, Post, Put, Query } from '@nestjs/common'; import { OperadorService } from './operador.service'; import { OperadorCreateDto } from './dto/operador-create.dto'; -import { OperadorLoginDto } from './dto/operador-login.dto'; import { OperadorOperadoresDto } from './dto/operador-operadores.dto'; import { OperadorUpdateDto } from './dto/operador-update.dto'; import { OperadorDto } from './dto/operador.dto'; @@ -18,14 +17,9 @@ export class OperadorController { ); } - @Post('login') - login(@Body() body: OperadorLoginDto) { - return this.operadorService.login(body.operador, body.password); - } - @Get('operador') operador(@Query() query: OperadorDto) { - return this.operadorService.findByOperador(query.operador); + return this.operadorService.findById(Number(query.id_operador)); } @Get('operadores') diff --git a/src/operador/operador.module.ts b/src/operador/operador.module.ts index ef5df32..2c5cd76 100644 --- a/src/operador/operador.module.ts +++ b/src/operador/operador.module.ts @@ -3,16 +3,19 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { OperadorController } from './operador.controller'; import { OperadorService } from './operador.service'; import { Operador } from './entity/operador.entity'; -import { InstitucionModule } from 'src/institucion/institucion.module'; -import { TipoUsuarioModule } from 'src/tipo-usuario/tipo-usuario.module'; +import { BcryptModule } from '../bcrypt/bcrypt.module'; +import { InstitucionModule } from '../institucion/institucion.module'; +import { TipoUsuarioModule } from '../tipo-usuario/tipo-usuario.module'; @Module({ imports: [ TypeOrmModule.forFeature([Operador]), + BcryptModule, InstitucionModule, TipoUsuarioModule, ], controllers: [OperadorController], providers: [OperadorService], + exports: [OperadorService], }) export class OperadorModule {} diff --git a/src/operador/operador.service.ts b/src/operador/operador.service.ts index c39acfc..d45dfbf 100644 --- a/src/operador/operador.service.ts +++ b/src/operador/operador.service.ts @@ -2,11 +2,12 @@ import { ConflictException, Injectable, NotFoundException, - UnauthorizedException, } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { Operador } from './entity/operador.entity'; +import { Institucion } from '../institucion/entity/institucion.entity'; +import { BcryptService } from 'src/bcrypt/bcrypt.service'; import { InstitucionService } from 'src/institucion/institucion.service'; import { TipoUsuarioService } from 'src/tipo-usuario/tipo-usuario.service'; @@ -14,22 +15,23 @@ import { TipoUsuarioService } from 'src/tipo-usuario/tipo-usuario.service'; export class OperadorService { constructor( @InjectRepository(Operador) private repository: Repository, - private isnstitucionService: InstitucionService, + private bcryptService: BcryptService, + private institucionService: InstitucionService, private tipoUsuarioService: TipoUsuarioService, ) {} async create(id_institucion: number, operador: string, password: string) { - const institucion = await this.isnstitucionService.findById(id_institucion); + const institucion = await this.institucionService.findById(id_institucion); const tipoUsuario = await this.tipoUsuarioService.findById(4); return this.repository .findOne({ operador, institucion }) - .then((existeOperador) => { + .then(async (existeOperador) => { if (existeOperador) throw new ConflictException( 'Ya existe un operador con ese nombre, intente de nuevo.', ); - /* Encriptar password */ + password = this.bcryptService.encriptar(password); return this.repository.save( this.repository.create({ institucion, @@ -47,13 +49,15 @@ export class OperadorService { id_institucion?: string; operador?: string; }) { - const busqueda: any = {}; + const busqueda: { operador?: string; institucion?: Institucion } = {}; const institucion = filtros.id_institucion - ? await this.isnstitucionService.findById(Number(filtros.id_institucion)) + ? await this.institucionService.findById(Number(filtros.id_institucion)) : null; + /* buscar like */ if (filtros.operador) busqueda.operador = filtros.operador; - if (filtros.id_institucion) busqueda.institucion = institucion; + if (institucion) busqueda.institucion = institucion; + /* falta página */ return this.repository.find(busqueda); } @@ -64,26 +68,21 @@ export class OperadorService { }); } - findByOperador(operador: string) { - return this.repository.findOne({ operador }).then((operador) => { - if (!operador) throw new NotFoundException('No existe este operador'); - return operador; - }); + findByOperador(id_institucion: number, operador: string) { + return this.institucionService + .findById(id_institucion) + .then((institucion) => this.repository.findOne({ institucion, operador })) + .then((operador) => { + if (!operador) throw new NotFoundException('No existe este operador.'); + return operador; + }); } - login(operador: string, password: string) { - return this.findByOperador(operador).then((operador) => { - if (operador.password !== password) - throw new UnauthorizedException('Contraseña incorrecta.'); - /* Crear JWT y regresarlo */ - return operador; - }); - } - - async update(attrs: Partial) { + update(attrs: Partial) { return this.findById(attrs.id_operador) .then((operador) => { - /* encriptar password */ + if (attrs.password) + attrs.password = this.bcryptService.encriptar(attrs.password); Object.assign(operador, attrs); return this.repository.save(operador); }) diff --git a/src/usuario/dto/usuario.dto.ts b/src/usuario/dto/usuario.dto.ts index 97940e5..193e7f3 100644 --- a/src/usuario/dto/usuario.dto.ts +++ b/src/usuario/dto/usuario.dto.ts @@ -2,5 +2,5 @@ import { IsNumberString } from 'class-validator'; export class UsuarioDto { @IsNumberString() - usuario: string; + id_usuario: string; } diff --git a/src/usuario/entity/usuario.entity.ts b/src/usuario/entity/usuario.entity.ts index f158a1c..228588f 100644 --- a/src/usuario/entity/usuario.entity.ts +++ b/src/usuario/entity/usuario.entity.ts @@ -22,10 +22,10 @@ export class Usuario { @Column({ type: Boolean, nullable: false, default: false }) multa: boolean; - @Column({ type: String, nullable: false, length: 60 }) + @Column({ type: String, nullable: true, length: 60 }) password: string; - @Column({ type: String, nullable: false, length: 10 }) + @Column({ type: String, nullable: true, length: 10 }) telefono: string; @Column({ type: String, nullable: false, length: 10 }) @@ -39,7 +39,9 @@ export class Usuario { @JoinColumn({ name: 'id_institucion' }) institucion: Institucion; - @ManyToOne(() => TipoUsuario, (tipoUsuario) => tipoUsuario.usuarios) + @ManyToOne(() => TipoUsuario, (tipoUsuario) => tipoUsuario.usuarios, { + eager: true, + }) @JoinColumn({ name: 'id_tipo_usuario' }) tipoUsuario: TipoUsuario; diff --git a/src/usuario/usuario.controller.ts b/src/usuario/usuario.controller.ts index b688282..ddcb3fe 100644 --- a/src/usuario/usuario.controller.ts +++ b/src/usuario/usuario.controller.ts @@ -1,11 +1,19 @@ -import { Body, Controller, Get, Post, Put, Query } from '@nestjs/common'; +import { + Body, + Controller, + Get, + Post, + Put, + Query, + UseGuards, +} from '@nestjs/common'; import { UsuarioService } from './usuario.service'; import { UsuarioEscolaresDto } from './dto/usuario-escolares.dto'; -import { UsuarioLoginDto } from './dto/usuario-login.dto'; import { UsuarioRegistrarDto } from './dto/usuario-registrar.dto'; import { UsuarioUpdateDto } from './dto/usuario-update.dto'; import { UsuarioUsuariosDto } from './dto/usuario-usuarios.dto'; import { UsuarioDto } from './dto/usuario.dto'; +import { AuthGuard } from '@nestjs/passport'; @Controller('usuario') export class UsuarioController { @@ -15,27 +23,25 @@ export class UsuarioController { @Get('escolares') escolares(@Query() query: UsuarioEscolaresDto) {} - @Post('login') - login(@Body() body: UsuarioLoginDto) { - return this.usuarioService.login(body.usuario, body.password); - } - @Post('registrar') registrar(@Body() body: UsuarioRegistrarDto) { return this.usuarioService.registrar(body.id_usuario, body.telefono); } @Put() + @UseGuards(AuthGuard('jwt')) update(@Body() body: UsuarioUpdateDto) { return this.usuarioService.update(body); } @Get('usuario') + @UseGuards(AuthGuard('jwt')) usuario(@Query() query: UsuarioDto) { - return this.usuarioService.findByUsuario(query.usuario); + return this.usuarioService.findById(Number(query.id_usuario)); } @Get('usuarios') + @UseGuards(AuthGuard('jwt')) usuarios(@Query() query: UsuarioUsuariosDto) { return this.usuarioService.findAll(query); } diff --git a/src/usuario/usuario.module.ts b/src/usuario/usuario.module.ts index c9c2b34..9069015 100644 --- a/src/usuario/usuario.module.ts +++ b/src/usuario/usuario.module.ts @@ -1,18 +1,25 @@ import { Module } from '@nestjs/common'; +import { PassportModule } from '@nestjs/passport'; import { TypeOrmModule } from '@nestjs/typeorm'; import { UsuarioController } from './usuario.controller'; import { UsuarioService } from './usuario.service'; import { Usuario } from './entity/usuario.entity'; +import { BcryptModule } from '../bcrypt/bcrypt.module'; +// import { CarreraModule } from '../carrera/carrera.module'; import { InstitucionModule } from '../institucion/institucion.module'; import { TipoUsuarioModule } from '../tipo-usuario/tipo-usuario.module'; @Module({ imports: [ + PassportModule.register({ defaultStrategy: 'jwt' }), TypeOrmModule.forFeature([Usuario]), + BcryptModule, + // CarreraModule, InstitucionModule, TipoUsuarioModule, ], controllers: [UsuarioController], providers: [UsuarioService], + exports: [UsuarioService], }) export class UsuarioModule {} diff --git a/src/usuario/usuario.service.ts b/src/usuario/usuario.service.ts index 179f3f3..4077312 100644 --- a/src/usuario/usuario.service.ts +++ b/src/usuario/usuario.service.ts @@ -1,11 +1,16 @@ import { + ConflictException, Injectable, NotFoundException, - UnauthorizedException, } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { Usuario } from './entity/usuario.entity'; +import { Carrera } from '../carrera/entity/carrera.entity'; +import { Institucion } from '../institucion/entity/institucion.entity'; +import { TipoUsuario } from '../tipo-usuario/entity/tipo-usuario.entity'; +import { BcryptService } from '../bcrypt/bcrypt.service'; +// import { CarreraService } from '../carrera/carrera.service'; import { InstitucionService } from '../institucion/institucion.service'; import { TipoUsuarioService } from '../tipo-usuario/tipo-usuario.service'; @@ -13,6 +18,8 @@ import { TipoUsuarioService } from '../tipo-usuario/tipo-usuario.service'; export class UsuarioService { constructor( @InjectRepository(Usuario) private repository: Repository, + private bcryptService: BcryptService, + // private carreraService: CarreraService, private institucionService: InstitucionService, private tipoUsuarioService: TipoUsuarioService, ) {} @@ -24,14 +31,31 @@ export class UsuarioService { id_tipo_usuario?: string; usuario?: string; }) { + const busqueda: { + carrera?: Carrera; + institucion?: Institucion; + tipoUsuario?: TipoUsuario; + usuario?: string; + } = {}; const institucion = filtros.id_institucion - ? this.institucionService.findById(Number(filtros.id_institucion)) + ? await this.institucionService.findById(Number(filtros.id_institucion)) : null; const tipoUsuario = filtros.id_tipo_usuario - ? this.tipoUsuarioService.findById(Number(filtros.id_tipo_usuario)) + ? await this.tipoUsuarioService.findById(Number(filtros.id_tipo_usuario)) : null; - const updtae = {}; /* Terminar cuando se tengan las fuinciones faltantes */ + // const carrera = filtros.id_carrera + // ? await this.carreraService.findById(Number(filtros.id_carrera)) + // : null; + + /* buscar like */ + if (filtros.usuario) busqueda.usuario = filtros.usuario; + if (institucion) busqueda.institucion = institucion; + if (tipoUsuario) busqueda.tipoUsuario = tipoUsuario; + // if (carrera) busqueda.carrera = carrera; + /* falta página */ + console.log(busqueda); + return this.repository.find(busqueda); } findById(id_usuario: number) { @@ -48,30 +72,56 @@ export class UsuarioService { }); } - login(usuario: string, password: string) { - return this.findByUsuario(usuario).then((usuario) => { - if (password !== usuario.password) - throw new UnauthorizedException('Contraseña incorrecta.'); - /* Crear JWT y regresarlo */ - return usuario; - }); + generarPassword = () => { + const length = 8; + const charset = + 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + const n = charset.length; + let password = ''; + + for (let i = 0; i < length; i++) + password += charset.charAt(Math.floor(Math.random() * n)); + return password; + }; + + passwordReset(id_usuario: number) { + const password = this.generarPassword(); + + return this.findById(id_usuario) + .then((usuario) => { + if (!usuario.password) + throw new ConflictException('No existe este usuario.'); + usuario.password = this.bcryptService.encriptar(password); + /* Mandar correo con contraseña */ + return this.repository.save(usuario); + }) + .then((_) => ({ + message: 'Se reseteo correctamente la constraseña del usuario.', + })); } registrar(id_usuario: number, telefono: string) { + const password = this.generarPassword(); + return this.findById(id_usuario) .then((usuario) => { + if (usuario.password) + throw new ConflictException( + 'Ya fue registrado este número de cuenta.', + ); usuario.telefono = telefono; - /* crear contraseña, encriptarla y mandarla por correo */ - usuario.password = 'hola'; + usuario.password = this.bcryptService.encriptar(password); + /* Mandar correo con contraseña */ return this.repository.save(usuario); }) .then((_) => ({ message: 'Se creo correctamente un usuario.' })); } - async update(attrs: Partial) { + update(attrs: Partial) { return this.findById(attrs.id_usuario) .then((usuario) => { - /* crear y encriptar password en caso de cambio de password */ + if (!usuario.password) + throw new ConflictException('No existe este usuario.'); Object.assign(usuario, attrs); return this.repository.save(usuario); })