diff --git a/config/logger.js b/config/logger.js new file mode 100644 index 0000000..8a6b275 --- /dev/null +++ b/config/logger.js @@ -0,0 +1,19 @@ +import winston from "winston"; + +const { combine, timestamp, printf } = winston.format; + +const myFormat = printf(({ level, message, timestamp }) => { + return `${timestamp} ${level}: ${JSON.stringify(message)}`; +}); + +export const logger = winston.createLogger({ + level: 'info', + format: combine( + timestamp(), + myFormat, + ), + transports: [ + new winston.transports.File({ filename: 'error.log', level: 'error' }), + new winston.transports.File({ filename: 'combined.log' }), + ], +}); diff --git a/controllers/group.js b/controllers/group.js index 6ca1779..50c6752 100644 --- a/controllers/group.js +++ b/controllers/group.js @@ -1,26 +1,72 @@ +import { logger } from "../config/logger"; import { groupService } from "../services/group"; -export const getGroup = async (req, res) => { - const groupData = await groupService.getById(req.params.id); - res.status(200).json(groupData); +export const getGroup = async (req, res, next) => { + const METHOD = 'getGroup'; + + try { + const groupData = await groupService.getById(req.params.id); + logger.log('info', JSON.stringify({ method: METHOD, id: req.params.id })); + res.status(200).json(groupData); + } + catch (error) { + const err = new DatabaseError(error.message); + next({ error: err, method: METHOD, params: { id: req.params.id } }); + } }; -export const getGroups = async (req, res) => { - const groupData = await groupService.getList(); - res.status(200).json(groupData); +export const getGroups = async (req, res, next) => { + const METHOD = 'getGroups'; + + try { + const groupData = await groupService.getList(); + logger.log('info', JSON.stringify({ method: METHOD })); + res.status(200).json(groupData); + } + catch (error) { + const err = new DatabaseError(error.message); + next({ error: err, method: METHOD }); + } }; -export const createGroup = async (req, res) => { - const groupData = await groupService.create(req.body); - res.status(200).json(groupData); +export const createGroup = async (req, res, next) => { + const METHOD = 'createGroup'; + + try { + const groupData = await groupService.create(req.body); + logger.log('info', JSON.stringify({ method: METHOD, params: req.body })); + res.status(200).json(groupData); + } + catch (error) { + const err = new DatabaseError(error.message); + next({ error: err, method: METHOD, params: req.body }); + } }; -export const editGroup = async (req, res) => { - const groupData = await groupService.edit(req.body); - res.status(200).json(groupData); +export const editGroup = async (req, res, next) => { + const METHOD = 'editGroup'; + + try { + const groupData = await groupService.edit(req.body); + logger.log('info', JSON.stringify({ method: METHOD, params: req.body })); + res.status(200).json(groupData); + } + catch (error) { + const err = new DatabaseError(error.message); + next({ error: err, method: METHOD, params: req.body }); + } }; -export const deleteGroup = async (req, res) => { - await groupService.delete(req.params.id); - res.status(200).send(); +export const deleteGroup = async (req, res, next) => { + const METHOD = 'deleteGroup'; + + try { + await groupService.delete(req.params.id); + logger.log('info', JSON.stringify({ method: METHOD, id: req.params.id })); + res.status(200).send(); + } + catch (error) { + const err = new DatabaseError(error.message); + next({ error: err, method: METHOD, params: { id: req.params.id } }); + } }; diff --git a/controllers/user.js b/controllers/user.js index 3d8b7a9..fce8c3c 100644 --- a/controllers/user.js +++ b/controllers/user.js @@ -1,26 +1,73 @@ +import { logger } from "../config/logger"; +import DatabaseError from "../helpers/errors/databaseError"; import { userService } from "../services/user"; -export const getUser = async (req, res) => { - const userData = await userService.getById(req.params.id); - res.status(200).json(userData); +export const getUser = async (req, res, next) => { + const METHOD = 'getUser'; + + try { + const userData = await userService.getById(req.params.id); + logger.log('info', JSON.stringify({ method: METHOD, id: req.params.id })); + res.status(200).json(userData); + } + catch (error) { + const err = new DatabaseError(error.message); + next({ error: err, method: METHOD, params: { id: req.params.id }}); + } }; -export const getUsers = async (req, res) => { - const usersData = await userService.getList(req.query.loginSubstring, req.query.limit); - res.status(200).json(usersData); +export const getUsers = async (req, res, next) => { + const METHOD = 'getUsers'; + + try { + const usersData = await userService.getList(req.query.loginSubstring, req.query.limit); + logger.log('info', JSON.stringify({ method: METHOD, substring: req.query.loginSubstring, limit: req.query.limit })); + res.status(200).json(usersData); + } + catch (error) { + const err = new DatabaseError(error.message); + next({ error: err, method: METHOD, params: { substring: req.query.loginSubstring, limit: req.query.limit } }); + } }; -export const createUser = async (req, res) => { - const userData = await userService.create(req.body); - res.status(200).json(userData); +export const createUser = async (req, res, next) => { + const METHOD = 'createUser'; + + try { + const userData = await userService.create(req.body); + logger.log('info', JSON.stringify({ method: METHOD, params: req.body })); + res.status(200).json(userData); + } + catch (error) { + const err = new DatabaseError(error.message); + next({ error: err, method: METHOD, params: req.body }); + } }; -export const editUser = async (req, res) => { - const userData = await userService.edit(req.body); - res.status(200).json(userData); +export const editUser = async (req, res, next) => { + const METHOD = 'editUser'; + + try { + const userData = await userService.edit(req.body); + logger.log('info', JSON.stringify({ method: METHOD, params: req.body })); + res.status(200).json(userData); + } + catch (error) { + const err = new DatabaseError(error.message); + next({ error: err, method: METHOD, params: req.body }); + } }; -export const deleteUser = async (req, res) => { - await userService.delete(req.params.id); - res.status(200).send(); +export const deleteUser = async (req, res, next) => { + const METHOD = 'deleteUser'; + + try { + await userService.delete(req.params.id); + logger.log('info', JSON.stringify({ method: METHOD, id: req.params.id })); + res.status(200).send(); + } + catch (error) { + const err = new DatabaseError(error.message); + next({ error: err, method: METHOD, params: { id: req.params.id } }); + } }; diff --git a/controllers/userGroup.js b/controllers/userGroup.js index e5fb7c4..cbfec37 100644 --- a/controllers/userGroup.js +++ b/controllers/userGroup.js @@ -1,11 +1,31 @@ +import { logger } from "../config/logger"; +import DatabaseError from "../helpers/errors/databaseError"; import { userGroupService } from "../services/userGroup" -export const getUserGroups = async (req, res) => { - const userGroupsData = await userGroupService.getList(); - res.status(200).json(userGroupsData); +export const getUserGroups = async (req, res, next) => { + const METHOD = 'getUserGroups'; + + try { + const userGroupsData = await userGroupService.getList(); + logger.log('info', JSON.stringify({ method: METHOD })); + res.status(200).json(userGroupsData); + } + catch (error) { + const err = new DatabaseError(error.message); + next({ error: err, method: METHOD }); + } }; -export const addUserGroup = async (req, res) => { - const userGroupData = await userGroupService.create(req.body); - res.status(200).json(userGroupData); +export const addUserGroup = async (req, res, next) => { + const METHOD = 'addUserGroup'; + + try { + const userGroupData = await userGroupService.create(req.body); + logger.log('info', JSON.stringify({ method: METHOD, params: req.body })); + res.status(200).json(userGroupData); + } + catch (error) { + const err = new DatabaseError(error.message); + next({ error: err, method: METHOD, params: req.body }); + } }; diff --git a/helpers/errors/databaseError.js b/helpers/errors/databaseError.js new file mode 100644 index 0000000..04e557e --- /dev/null +++ b/helpers/errors/databaseError.js @@ -0,0 +1,7 @@ +import ExtendError from './errorExtention'; + +export default class DatabaseError extends ExtendError { + constructor(message) { + super(500, message || 'Database Error') + } +} diff --git a/helpers/errors/errorExtention.js b/helpers/errors/errorExtention.js new file mode 100644 index 0000000..62d73d6 --- /dev/null +++ b/helpers/errors/errorExtention.js @@ -0,0 +1,17 @@ +export default class ExtendError extends Error { + constructor(status, message) { + super(message); + this.status = status; + } + + getResponse() { + return { + status: 'Failed', + message: this.message + }; + } + + getStatus() { + return this.status; + } +} diff --git a/helpers/errors/errorHandler.js b/helpers/errors/errorHandler.js new file mode 100644 index 0000000..16ee2c9 --- /dev/null +++ b/helpers/errors/errorHandler.js @@ -0,0 +1,16 @@ +import { logger } from "../../config/logger"; +import DatabaseError from "./databaseError"; +import NotFoundError from "./notFoundError"; + +const customErrors = [DatabaseError, NotFoundError]; + +export const customErrorHandler = ({ error, method, params }, res) => { + if (customErrors.includes(error.constructor)) { + logger.log('error', JSON.stringify({ status: error.status, message: error.message, method: method, params: params })); + + return res.status(error.status).json({ status: error.status, message: error.message }); + } + + logger.log('error', JSON.stringify({ unhandledError: error.message, method: method, params: params })); + throw new Error(error); +}; diff --git a/helpers/errors/notFoundError.js b/helpers/errors/notFoundError.js new file mode 100644 index 0000000..627d7a2 --- /dev/null +++ b/helpers/errors/notFoundError.js @@ -0,0 +1,7 @@ +import ExtendError from './errorExtention'; + +export default class NotFoundError extends ExtendError { + constructor(message) { + super(404, message || 'Not Found') + } +} diff --git a/helpers/initLogger.js b/helpers/initLogger.js new file mode 100644 index 0000000..de8ed43 --- /dev/null +++ b/helpers/initLogger.js @@ -0,0 +1,24 @@ +import { logger } from "../config/logger"; + +export const initLogger = app => { + app.use((req, res, next) => { + const dataMessage = []; + + dataMessage.push(JSON.stringify({ url: req.originalUrl })); + + if (!isObjEmpty(req.params)) { + dataMessage.push(JSON.stringify({ params: req.params })); + } + + if (!isObjEmpty(req.body)) { + dataMessage.push(JSON.stringify({ body: req.body })); + } + + logger.log('info', dataMessage.toString()); + next(); + }); + + const isObjEmpty = obj => { + return Object.keys(obj).length === 0 && obj.constructor === Object; + } +} \ No newline at end of file diff --git a/helpers/users.csv b/helpers/users.csv deleted file mode 100644 index 8657a2f..0000000 --- a/helpers/users.csv +++ /dev/null @@ -1,5 +0,0 @@ -id;login;password;age;isDeleted -3b0b3729-fc84-4b8b-8b9d-35dd6405f8d22;Ibragim;pass1;21;false -3b0b3729-fc84-4b8b-8b9d-35dd6405f8d32;Mikhail;pass2;51;false -3b0b3729-fc84-4b8b-8b9d-35dd6405f8d42;Fahrid;pass3;18;false -3b0b3729-fc84-4b8b-8b9d-35dd6405f8d52;Magarita;pass4;28;true \ No newline at end of file diff --git a/helpers/users_from_csv.js b/helpers/users_from_csv.js deleted file mode 100644 index e5d8d93..0000000 --- a/helpers/users_from_csv.js +++ /dev/null @@ -1,17 +0,0 @@ -import fs from 'fs'; -import csv from 'csvtojson'; - -const readStream = fs.createReadStream("./helpers/users.csv"); -const users = new Array(); - -csv({ - checkType: true, - delimiter: [";"], -}) - .fromStream(readStream) - .subscribe((json) => { - users.push(json); - }) - .then(function () {}, function(err) { console.error(err)}); - -export default users; diff --git a/loaders/index.js b/loaders/index.js index b56e18c..e0eefc1 100644 --- a/loaders/index.js +++ b/loaders/index.js @@ -1,14 +1,13 @@ import { routerLoader } from "./routerLoader"; -import { sequelize } from "../config/db"; +import { logger } from "../config/logger"; export const loaders = (app) => { - sequelize - .authenticate() - .then(() => { - console.log('Connection to database!'); - }) - .catch(err => { - console.log('Can\'t connect to database!'); + process.on('uncaughtException', err => { + logger.log('error', 'UncaughtException happens... System shut down' + JSON.stringify(err)); + process.exit(1); + }); + process.on('unhandledRejection', err => { + logger.log('error', 'UnhandledRejection happens... Please, stay on your place.' + JSON.stringify(err)); }); routerLoader(app); diff --git a/loaders/routerLoader.js b/loaders/routerLoader.js index 65b72e7..3414340 100644 --- a/loaders/routerLoader.js +++ b/loaders/routerLoader.js @@ -1,8 +1,24 @@ import { json } from "express"; import { API_PREFIX } from "../config"; +import { customErrorHandler } from "../helpers/errors/errorHandler"; +import NotFoundError from "../helpers/errors/notFoundError"; +import { initLogger } from "../helpers/initLogger"; import { apiRouter } from "../routers/index"; export const routerLoader = (app) => { app.use(json()); + + initLogger(app); + app.use(API_PREFIX, apiRouter()); + + app.use((req, res, next) => { + const error = new NotFoundError(); + next({ error }); + }); + + app.use((error, req, res, next) => { + customErrorHandler(error, res); + next(); + }); }; diff --git a/models/user.js b/models/user.js index ea29b94..d1aa53b 100644 --- a/models/user.js +++ b/models/user.js @@ -1,9 +1,11 @@ import { User } from "../db-layer/userDB"; import { Op } from "sequelize"; +import DatabaseError from "../helpers/errors/databaseError"; +import NotFoundError from "../helpers/errors/notFoundError"; export const userModel = { getById: (userId) => { - return User.findByPk(userId).catch((err) => console.error(err)); + return User.findByPk(userId); }, getList: (loginSubstr, limit) => { diff --git a/package-lock.json b/package-lock.json index a04f080..edbeb76 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1216,6 +1216,16 @@ } } }, + "@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "@hapi/accept": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@hapi/accept/-/accept-5.0.1.tgz", @@ -1695,6 +1705,11 @@ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + }, "babel-loader": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz", @@ -1944,6 +1959,30 @@ "mimic-response": "^1.0.0" } }, + "color": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + }, + "dependencies": { + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + } + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1956,8 +1995,30 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "color-string": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + }, + "colorspace": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", + "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", + "requires": { + "color": "3.0.x", + "text-hex": "1.0.x" + } }, "commondir": { "version": "1.0.1", @@ -2051,6 +2112,11 @@ } } }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2174,6 +2240,11 @@ "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -2698,6 +2769,16 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" + }, + "fecha": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.0.tgz", + "integrity": "sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg==" + }, "file-entry-cache": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", @@ -2794,6 +2875,11 @@ "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", "dev": true }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -3025,8 +3111,7 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { "version": "1.3.5", @@ -3145,6 +3230,11 @@ "has-symbols": "^1.0.1" } }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + }, "is-string": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", @@ -3174,8 +3264,7 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isexe": { "version": "2.0.0", @@ -3235,6 +3324,11 @@ "json-buffer": "3.0.0" } }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "latest-version": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", @@ -3332,6 +3426,18 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" }, + "logform": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz", + "integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==", + "requires": { + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "triple-beam": "^1.3.0" + } + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -3579,6 +3685,14 @@ "wrappy": "1" } }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "requires": { + "fn.name": "1.x.x" + } + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -3852,6 +3966,11 @@ "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", "dev": true }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -3997,6 +4116,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.4.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", @@ -4254,6 +4383,21 @@ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", "dev": true }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } + }, "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", @@ -4343,6 +4487,11 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -4406,6 +4555,21 @@ "es-abstract": "^1.17.5" } }, + "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": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -4461,6 +4625,11 @@ "integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==", "dev": true }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -4506,6 +4675,11 @@ "nopt": "~1.0.10" } }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, "tsconfig-paths": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", @@ -4671,6 +4845,11 @@ "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", @@ -4725,6 +4904,55 @@ "string-width": "^4.0.0" } }, + "winston": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", + "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "requires": { + "@dabh/diagnostics": "^2.0.2", + "async": "^3.1.0", + "is-stream": "^2.0.0", + "logform": "^2.2.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.0" + } + }, + "winston-transport": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", + "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "requires": { + "readable-stream": "^2.3.7", + "triple-beam": "^1.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "wkx": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", diff --git a/package.json b/package.json index c447cf1..f65bd98 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "pg": "^8.3.2", "pg-hstore": "^2.3.3", "regenerator-runtime": "^0.13.7", - "sequelize": "^6.3.4" + "sequelize": "^6.3.4", + "winston": "^3.3.3" } } diff --git a/validation/group.js b/validation/group.js index 2b8b32d..42928eb 100644 --- a/validation/group.js +++ b/validation/group.js @@ -13,5 +13,33 @@ const groupEditSchema = Joi.object({ id: Joi.string().pattern(uuidV4Pattern).required() }).or('name', 'permissions'); -export const groupCreateValidator = createValidator().body(groupCreateSchema); -export const groupEditValidator = createValidator().body(groupEditSchema); +export const groupCreateValidator = async (req, res, next) => { + const { error } = groupCreateSchema.validate({ + name: req.body.name, + permissions: req.body.permissions, + }); + + if (error) { + logger.log('error', JSON.stringify(error.message)); + + return res.status(400).json(error.details); + } + + return next(); +}; + +export const groupEditValidator = async (req, res, next) => { + const { error } = groupEditSchema.validate({ + id: req.body.id, + name: req.body.name, + permissions: req.body.permissions, + }); + + if (error) { + logger.log('error', JSON.stringify(error.message)); + + return res.status(400).json(error.details); + } + + return next(); +}; diff --git a/validation/user.js b/validation/user.js index 7cd2ef4..f43ff59 100644 --- a/validation/user.js +++ b/validation/user.js @@ -1,6 +1,7 @@ import Joi from "@hapi/joi"; import { createValidator } from "express-joi-validation"; import { uuidV4Pattern } from "../config"; +import { logger } from "../config/logger"; const userCreateSchema = Joi.object({ login: Joi.string().required(), @@ -15,5 +16,35 @@ const userEditSchema = Joi.object({ id: Joi.string().pattern(uuidV4Pattern).required() }).or('login', 'password', 'age'); -export const userCreateValidator = createValidator().body(userCreateSchema); -export const userEditValidator = createValidator().body(userEditSchema); +export const userCreateValidator = async (req, res, next) => { + const { error } = userCreateSchema.validate({ + login: req.body.login, + password: req.body.password, + age: req.body.age + }); + + if (error) { + logger.log('error', JSON.stringify(error.message)); + + return res.status(400).json(error.details); + } + + return next(); +}; + +export const userEditValidator = async (req, res, next) => { + const { error } = userEditSchema.validate({ + id: req.body.id, + login: req.body.login, + password: req.body.password, + age: req.body.age + }); + + if (error) { + logger.log('error', JSON.stringify(error.message)); + + return res.status(400).json(error.details); + } + + return next(); +}; diff --git a/validation/userGroup.js b/validation/userGroup.js index b29043f..512f4fd 100644 --- a/validation/userGroup.js +++ b/validation/userGroup.js @@ -7,4 +7,17 @@ const userGroupAddSchema = Joi.object({ userIds: Joi.array().items(Joi.string().pattern(uuidV4Pattern).required()), }); -export const userGroupAddValidator = createValidator().body(userGroupAddSchema); +export const userGroupAddValidator = async (req, res, next) => { + const { error } = userGroupAddSchema.validate({ + groupId: req.body.groupId, + userIds: req.body.userIds + }); + + if (error) { + logger.log('error', JSON.stringify(error.message)); + + return res.status(400).json(error.details); + } + + return next(); +};