From 139e47261e9da41882073b8005d2f8c3a04b0093 Mon Sep 17 00:00:00 2001 From: Yuri Lysov Date: Sat, 6 Nov 2021 00:04:12 +0300 Subject: [PATCH 1/3] prepare repository to task 3 requirements --- .env | 3 + .eslintrc | 16 +- package-lock.json | 259 +++++++++++++++++++++++++++- package.json | 6 +- src/module-3/controllers/index.ts | 1 + src/module-3/data-access/connect.ts | 0 src/module-3/data-access/index.ts | 17 ++ src/module-3/data-access/types.ts | 9 + src/module-3/index.ts | 26 +++ 9 files changed, 325 insertions(+), 12 deletions(-) create mode 100644 .env create mode 100644 src/module-3/controllers/index.ts create mode 100644 src/module-3/data-access/connect.ts create mode 100644 src/module-3/data-access/index.ts create mode 100644 src/module-3/data-access/types.ts create mode 100644 src/module-3/index.ts diff --git a/.env b/.env new file mode 100644 index 0000000..9a6811d --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +DB_PASS=Rac8q1BPNHPg47UQqWEvKqRxkLitfCzJ +DB_URL=postgres://wtsmveqq:Rac8q1BPNHPg47UQqWEvKqRxkLitfCzJ@fanny.db.elephantsql.com/wtsmveqq +DB_DEFAULT=wtsmveqq \ No newline at end of file diff --git a/.eslintrc b/.eslintrc index 804ae9f..fe983aa 100644 --- a/.eslintrc +++ b/.eslintrc @@ -101,13 +101,13 @@ "no-script-url": 2, "no-self-compare": 2, "no-sequences": 2, - "no-unused-expressions": [ - 2, - { - "allowShortCircuit": true, - "allowTernary": false - } - ], + // "no-unused-expressions": [ + // 2, + // { + // "allowShortCircuit": true, + // "allowTernary": false + // } + // ], "no-useless-call": 2, "no-with": 2, "radix": 2, @@ -139,7 +139,7 @@ "no-shadow": 2, "no-undef-init": 2, "no-undef": 2, - "no-unused-vars": 2, + // "no-unused-vars": 2, "callback-return": 2, "no-mixed-requires": 2, "no-path-concat": 2, diff --git a/package-lock.json b/package-lock.json index f5b78e4..59150ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1799,6 +1799,11 @@ "color-convert": "^2.0.1" } }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + }, "anymatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", @@ -1998,6 +2003,11 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" + }, "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", @@ -2366,6 +2376,16 @@ "is-obj": "^2.0.0" } }, + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + }, + "dottie": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", + "integrity": "sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg==" + }, "duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", @@ -3203,6 +3223,11 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "inflection": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.1.tgz", + "integrity": "sha512-dldYtl2WlN0QDkIDtg8+xFwOS2Tbmp12t1cHa5/YClU6ZQjTFm7B66UcVbh9NQB+HvT5BAd2t5+yKsBkw5pcqA==" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -3580,7 +3605,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "requires": { "yallist": "^4.0.0" } @@ -3683,6 +3707,19 @@ "minimist": "^1.2.5" } }, + "moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + }, + "moment-timezone": { + "version": "0.5.33", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.33.tgz", + "integrity": "sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w==", + "requires": { + "moment": ">= 2.9.0" + } + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -3882,6 +3919,11 @@ } } }, + "packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -3943,6 +3985,68 @@ "through": "~2.3" } }, + "pg": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.1.tgz", + "integrity": "sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA==", + "requires": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.5.0", + "pg-pool": "^3.4.1", + "pg-protocol": "^1.5.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + } + }, + "pg-connection-string": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" + }, + "pg-hstore": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/pg-hstore/-/pg-hstore-2.3.4.tgz", + "integrity": "sha512-N3SGs/Rf+xA1M2/n0JBiXFDVMzdekwLZLAO0g7mpDY9ouX+fDI7jS6kTq3JujmYbtNSJ53TJ0q4G98KVZSM4EA==", + "requires": { + "underscore": "^1.13.1" + } + }, + "pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-pool": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.4.1.tgz", + "integrity": "sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ==" + }, + "pg-protocol": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", + "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" + }, + "pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "requires": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + } + }, + "pgpass": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz", + "integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==", + "requires": { + "split2": "^3.1.1" + } + }, "picomatch": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", @@ -3973,6 +4077,29 @@ "find-up": "^3.0.0" } }, + "postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" + }, + "postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" + }, + "postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "requires": { + "xtend": "^4.0.0" + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -4084,6 +4211,16 @@ } } }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, "readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -4208,6 +4345,14 @@ "lowercase-keys": "^1.0.0" } }, + "retry-as-promised": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz", + "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==", + "requires": { + "any-promise": "^1.3.0" + } + }, "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -4306,6 +4451,54 @@ } } }, + "sequelize": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.9.0.tgz", + "integrity": "sha512-tFROh9T9GgyY6aTV2+aGdfVNvrppuTOo1EFln9AtV8wXJTOOr7Nan7pZum5oLy87CGWl0YeHzAwg99tz04OqNA==", + "requires": { + "debug": "^4.1.1", + "dottie": "^2.0.0", + "inflection": "1.13.1", + "lodash": "^4.17.20", + "moment": "^2.26.0", + "moment-timezone": "^0.5.31", + "retry-as-promised": "^3.2.0", + "semver": "^7.3.2", + "sequelize-pool": "^6.0.0", + "toposort-class": "^1.0.1", + "uuid": "^8.1.0", + "validator": "^13.6.0", + "wkx": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "sequelize-pool": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz", + "integrity": "sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg==" + }, "serve-static": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", @@ -4393,6 +4586,14 @@ "through": "2" } }, + "split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "requires": { + "readable-stream": "^3.0.0" + } + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -4443,6 +4644,21 @@ "define-properties": "^1.1.3" } }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -4511,6 +4727,11 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, + "toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" + }, "touch": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", @@ -4662,6 +4883,11 @@ } } }, + "underscore": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", + "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==" + }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -4755,11 +4981,21 @@ "prepend-http": "^2.0.0" } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, "v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", @@ -4775,6 +5011,11 @@ "homedir-polyfill": "^1.0.1" } }, + "validator": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -4811,6 +5052,14 @@ "string-width": "^4.0.0" } }, + "wkx": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", + "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", + "requires": { + "@types/node": "*" + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -4851,11 +5100,15 @@ "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", "dev": true }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } } diff --git a/package.json b/package.json index 4e45886..c8fdb30 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "task2": "nodemon --exec babel-node ./src/module-2/index.ts --extensions .ts", + "module-3": "nodemon --exec babel-node ./src/module-3/index.ts --extensions .ts", "lint": "eslint . --ext .ts" }, "author": "", @@ -14,10 +14,14 @@ "@types/event-stream": "^3.3.34", "@types/node": "^16.10.1", "csvtojson": "^2.0.10", + "dotenv": "^10.0.0", "event-stream": "^4.0.1", "express": "^4.17.1", "express-joi-validation": "^5.0.0", "joi": "^17.4.2", + "pg": "^8.7.1", + "pg-hstore": "^2.3.4", + "sequelize": "^6.9.0", "tslint": "^6.1.3", "typescript": "^4.4.3" }, diff --git a/src/module-3/controllers/index.ts b/src/module-3/controllers/index.ts new file mode 100644 index 0000000..2f0e4fb --- /dev/null +++ b/src/module-3/controllers/index.ts @@ -0,0 +1 @@ +// import express, { Request, Response } from "express"; diff --git a/src/module-3/data-access/connect.ts b/src/module-3/data-access/connect.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/module-3/data-access/index.ts b/src/module-3/data-access/index.ts new file mode 100644 index 0000000..b6e15aa --- /dev/null +++ b/src/module-3/data-access/index.ts @@ -0,0 +1,17 @@ +// import { DataTypes, Model, Sequelize } from "sequelize"; + +// class User extends Model {} + +// const sequelize = new Sequelize('postgres://user:pass@example.com:5432/dbname'); + +// User.init( +// { +// username: DataTypes.STRING, +// birthday: DataTypes.DATE +// }, +// { sequelize, modelName: "user" } +// ); + +// const addUser = ({ login, password, age }: AddUserParams) => { + +// }; diff --git a/src/module-3/data-access/types.ts b/src/module-3/data-access/types.ts new file mode 100644 index 0000000..b50acfc --- /dev/null +++ b/src/module-3/data-access/types.ts @@ -0,0 +1,9 @@ +export type User = { + id: string; + login: string; + password: string; + age: number; + isDeleted: boolean; +}; + +export type AddUserParams = Pick; diff --git a/src/module-3/index.ts b/src/module-3/index.ts new file mode 100644 index 0000000..071df72 --- /dev/null +++ b/src/module-3/index.ts @@ -0,0 +1,26 @@ +import * as dotenv from "dotenv"; +import express from "express"; +import { Sequelize } from "sequelize"; + +// class User extends Model {} + +dotenv.config(); + +const app = express(); + +app.use(express.json()); +// app.use("/api/users", usersRouter); + +/* TODO: need to move in separated files */ +const DB_URL = process.env.DB_URL; + +const sequelize = new Sequelize(DB_URL); + +app.listen(3000, async () => { + try { + await sequelize.authenticate(); + console.log("Connection has been established successfully."); + } catch (error) { + console.error("Unable to connect to the database:", error); + } +}); From 3c23ca24666530aba33066bf683e8607fc498698 Mon Sep 17 00:00:00 2001 From: Yuri Lysov Date: Sat, 6 Nov 2021 23:56:34 +0300 Subject: [PATCH 2/3] Prepare the app with new configurations according to homework's requirements --- src/module-3/controllers/index.ts | 1 - src/module-3/controllers/users.ts | 85 ++++++++++++++++++++ src/module-3/controllers/utils.ts | 4 + src/module-3/controllers/validation/users.ts | 9 +++ src/module-3/data-access/connect.ts | 0 src/module-3/data-access/index.ts | 21 ++--- src/module-3/data-access/types.ts | 9 --- src/module-3/index.ts | 36 ++++----- src/module-3/models/user.ts | 26 ++++++ src/module-3/services/users.ts | 77 ++++++++++++++++++ src/module-3/types.ts | 10 +++ 11 files changed, 233 insertions(+), 45 deletions(-) delete mode 100644 src/module-3/controllers/index.ts create mode 100644 src/module-3/controllers/users.ts create mode 100644 src/module-3/controllers/utils.ts create mode 100644 src/module-3/controllers/validation/users.ts delete mode 100644 src/module-3/data-access/connect.ts delete mode 100644 src/module-3/data-access/types.ts create mode 100644 src/module-3/models/user.ts create mode 100644 src/module-3/services/users.ts create mode 100644 src/module-3/types.ts diff --git a/src/module-3/controllers/index.ts b/src/module-3/controllers/index.ts deleted file mode 100644 index 2f0e4fb..0000000 --- a/src/module-3/controllers/index.ts +++ /dev/null @@ -1 +0,0 @@ -// import express, { Request, Response } from "express"; diff --git a/src/module-3/controllers/users.ts b/src/module-3/controllers/users.ts new file mode 100644 index 0000000..a64a098 --- /dev/null +++ b/src/module-3/controllers/users.ts @@ -0,0 +1,85 @@ +import express from "express"; +import { createValidator } from "express-joi-validation"; +import { UserModel } from "../types"; +import * as UsersService from "../services/users"; +import { isNull } from "./utils"; +import userValidationSchema from "./validation/users"; + +const validator = createValidator(); +const router = express.Router(); + +/* Get users list */ + +router.get("/", async (req, res) => { + try { + const users = await UsersService.getAutoSuggestUsers( + req.body.loginSubstring, + req.body.limit + ); + res.status(200).send(users); + } catch (e) { + res.status(500).send(e.message); + } +}); + +/* Find user by id */ + +router.get("/:id", async (req, res) => { + try { + const id = req.params.id; + const user = await UsersService.find(id); + if (user) { + return res.status(200).send(user); + } + res.status(404).send("User not found"); + } catch (e) { + res.status(500).send(e.message); + } +}); + +/* Create user */ + +router.post("/", validator.body(userValidationSchema), async (req, res) => { + try { + const body: UserModel = req.body; + const isSuccess = await UsersService.create(body); + if (!isSuccess) { + return res.status(400).send("User with this login is already exists"); + } + res.redirect("/api/users"); + } catch (e) { + res.status(500).send(e.message); + } +}); + +/* Delete user */ + +router.delete("/:id", async (req, res) => { + try { + const id = req.params.id; + const isSuccess = await UsersService.remove(id); + if (isNull(isSuccess)) { + return res.status(404).send("User with this id is not found"); + } + res.redirect("/api/users"); + } catch (e) { + res.status(500).send(e.message); + } +}); + +/* Update user */ + +router.put("/:id", validator.body(userValidationSchema), async (req, res) => { + try { + const id = req.params.id; + const isSuccess = await UsersService.update(id, req.body); + if (!isSuccess) { + return res.status(404).send("User with this id is not found"); + } + res.redirect("/api/users"); + } catch (e) { + res.status(500).send(e.message); + } +}); + +export default router; diff --git a/src/module-3/controllers/utils.ts b/src/module-3/controllers/utils.ts new file mode 100644 index 0000000..7b7b56e --- /dev/null +++ b/src/module-3/controllers/utils.ts @@ -0,0 +1,4 @@ +import { Model } from "sequelize/types"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export const isNull = (value: Model) => value === null; diff --git a/src/module-3/controllers/validation/users.ts b/src/module-3/controllers/validation/users.ts new file mode 100644 index 0000000..51527c8 --- /dev/null +++ b/src/module-3/controllers/validation/users.ts @@ -0,0 +1,9 @@ +import joi from "joi"; + +const userValidationSchema = joi.object().keys({ + login: joi.string().alphanum().min(3).max(10).required(), + password: joi.string().alphanum().required(), + age: joi.number().min(4).max(130).required() +}); + +export default userValidationSchema; diff --git a/src/module-3/data-access/connect.ts b/src/module-3/data-access/connect.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/module-3/data-access/index.ts b/src/module-3/data-access/index.ts index b6e15aa..daaef92 100644 --- a/src/module-3/data-access/index.ts +++ b/src/module-3/data-access/index.ts @@ -1,17 +1,12 @@ -// import { DataTypes, Model, Sequelize } from "sequelize"; +import * as dotenv from "dotenv"; +import { Sequelize } from "sequelize"; -// class User extends Model {} +dotenv.config(); -// const sequelize = new Sequelize('postgres://user:pass@example.com:5432/dbname'); +if (!process.env.DB_URL) { + process.exit(1); +} -// User.init( -// { -// username: DataTypes.STRING, -// birthday: DataTypes.DATE -// }, -// { sequelize, modelName: "user" } -// ); +const DB_URL = process.env.DB_URL; -// const addUser = ({ login, password, age }: AddUserParams) => { - -// }; +export default new Sequelize(DB_URL); diff --git a/src/module-3/data-access/types.ts b/src/module-3/data-access/types.ts deleted file mode 100644 index b50acfc..0000000 --- a/src/module-3/data-access/types.ts +++ /dev/null @@ -1,9 +0,0 @@ -export type User = { - id: string; - login: string; - password: string; - age: number; - isDeleted: boolean; -}; - -export type AddUserParams = Pick; diff --git a/src/module-3/index.ts b/src/module-3/index.ts index 071df72..75b727d 100644 --- a/src/module-3/index.ts +++ b/src/module-3/index.ts @@ -1,26 +1,18 @@ -import * as dotenv from "dotenv"; import express from "express"; -import { Sequelize } from "sequelize"; - -// class User extends Model {} - -dotenv.config(); +import usersRouter from "./controllers/users"; +import db from "./data-access"; const app = express(); -app.use(express.json()); -// app.use("/api/users", usersRouter); - -/* TODO: need to move in separated files */ -const DB_URL = process.env.DB_URL; - -const sequelize = new Sequelize(DB_URL); - -app.listen(3000, async () => { - try { - await sequelize.authenticate(); - console.log("Connection has been established successfully."); - } catch (error) { - console.error("Unable to connect to the database:", error); - } -}); +app.listen(3000, () => + db + .authenticate() + .then(() => + console.log( + "Connection has been established successfully.\nServer started..." + ) + ) + .then(() => app.use(express.json())) + .then(() => app.use("/api/users", usersRouter)) + .catch((err) => console.error(err)) +); diff --git a/src/module-3/models/user.ts b/src/module-3/models/user.ts new file mode 100644 index 0000000..af34638 --- /dev/null +++ b/src/module-3/models/user.ts @@ -0,0 +1,26 @@ +import { DataTypes, Model, ModelCtor } from "sequelize"; +import db from "../data-access"; +import { UserModel } from "../types"; + +const User: ModelCtor> = db.define( + "users", + { + login: { + type: DataTypes.STRING + }, + password: { + type: DataTypes.STRING + }, + age: { + type: DataTypes.NUMBER + }, + isDeleted: { + type: DataTypes.BOOLEAN + } + }, + { + timestamps: false + } +); + +export default User; diff --git a/src/module-3/services/users.ts b/src/module-3/services/users.ts new file mode 100644 index 0000000..6637d8f --- /dev/null +++ b/src/module-3/services/users.ts @@ -0,0 +1,77 @@ +import { UserModel } from "../types"; +import User from "../models/user"; + +export const getUsersList = async () => + User.findAll({ + where: { + isDeleted: false + } + }); + +export const getAutoSuggestUsers = async (subsrt?: string, limit = 3) => { + let users = await getUsersList(); + + if (subsrt && limit && users.length) { + users = users + .filter((e) => e.getDataValue("login").indexOf(String(subsrt)) !== -1) + .slice(0, limit) + .sort((a, b) => + a.getDataValue("login").localeCompare(b.getDataValue("login")) + ); + } + + return users; +}; + +export const find = async (id: string) => + User.findOne({ + where: { + id, + isDeleted: false + } + }); + +export const create = async (model: UserModel) => { + const { login } = model; + const user = await User.findOne({ + where: { + login + } + }); + + if (user) { + return null; + } + + return User.create({ + ...model, + isDeleted: false + }); +}; + +export const remove = async (id: string) => { + const user = await find(id); + + if (!user) { + return null; + } + + return user.update({ + isDeleted: true + }); +}; + +export const update = async (id: string, model: UserModel) => { + const user = await find(id); + const { login, password, age } = model; + + if (!user) { + return null; + } + + return user.update({ + login, + password, + age + }); +}; diff --git a/src/module-3/types.ts b/src/module-3/types.ts new file mode 100644 index 0000000..8364b99 --- /dev/null +++ b/src/module-3/types.ts @@ -0,0 +1,10 @@ +export interface UserModel extends BaseUser { + login: string; + password: string; + age: number; +} + +export interface BaseUser { + id?: string; + isDeleted?: boolean; +} From a7863c823f29c74f29ebe197e689394e08fa0833 Mon Sep 17 00:00:00 2001 From: Yuri Lysov Date: Sat, 13 Nov 2021 19:55:31 +0300 Subject: [PATCH 3/3] fix security issues --- .env | 3 --- .gitignore | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) delete mode 100644 .env diff --git a/.env b/.env deleted file mode 100644 index 9a6811d..0000000 --- a/.env +++ /dev/null @@ -1,3 +0,0 @@ -DB_PASS=Rac8q1BPNHPg47UQqWEvKqRxkLitfCzJ -DB_URL=postgres://wtsmveqq:Rac8q1BPNHPg47UQqWEvKqRxkLitfCzJ@fanny.db.elephantsql.com/wtsmveqq -DB_DEFAULT=wtsmveqq \ No newline at end of file diff --git a/.gitignore b/.gitignore index 22baab3..345dabd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules -.vscode \ No newline at end of file +.vscode +.env \ No newline at end of file