From cc51fe6095b0a3b195f58d71bb28201ebd0f7885 Mon Sep 17 00:00:00 2001 From: Nikiroy78 <35032449+Nikiroy78@users.noreply.github.com> Date: Sun, 1 Oct 2023 22:05:41 +0300 Subject: [PATCH] Backend push --- .gitignore | 4 +- api/v1/index.js | 35 ++++- api/v1/methods/create-item.js | 64 ++++++++- api/v1/methods/edit-item.js | 84 ++++++++++++ api/v1/methods/get-authors.js | 79 +++++++++++ api/v1/methods/get-muzic.js | 110 +++++++++++++++ api/v1/methods/remove-item.js | 63 +++++++++ api/v1/response-wrapper.js | 29 +++- config.json | 11 +- database.js | 119 ++++++++++++++++- db-dump/install-it.sql | Bin 3108 -> 4270 bytes logger.js | 2 +- logger/1696077968979.log | 32 ----- logger/1696078110139.log | 31 ----- logger/1696078148809.log | 31 ----- logger/1696078152801.log | 31 ----- logger/1696078155304.log | 32 ----- logger/1696078172286.log | 31 ----- logger/1696078360031.log | 27 ---- logger/1696078390481.log | 31 ----- logger/1696078402689.log | 27 ---- logger/1696078452280.log | 31 ----- logger/1696078455190.log | 32 ----- logger/1696078464012.log | 31 ----- logger/1696078471980.log | 27 ---- logger/1696078550536.log | 31 ----- logger/1696078647763.log | 27 ---- logger/1696079964979.log | 23 ---- package-lock.json | 243 ++++++++++++++++++++++++++++++++++ package.json | 1 + server.js | 17 ++- 31 files changed, 833 insertions(+), 503 deletions(-) create mode 100644 api/v1/methods/edit-item.js create mode 100644 api/v1/methods/get-authors.js create mode 100644 api/v1/methods/get-muzic.js create mode 100644 api/v1/methods/remove-item.js delete mode 100644 logger/1696077968979.log delete mode 100644 logger/1696078110139.log delete mode 100644 logger/1696078148809.log delete mode 100644 logger/1696078152801.log delete mode 100644 logger/1696078155304.log delete mode 100644 logger/1696078172286.log delete mode 100644 logger/1696078360031.log delete mode 100644 logger/1696078390481.log delete mode 100644 logger/1696078402689.log delete mode 100644 logger/1696078452280.log delete mode 100644 logger/1696078455190.log delete mode 100644 logger/1696078464012.log delete mode 100644 logger/1696078471980.log delete mode 100644 logger/1696078550536.log delete mode 100644 logger/1696078647763.log delete mode 100644 logger/1696079964979.log diff --git a/.gitignore b/.gitignore index 4a518b6..e06b9f1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ node_modules/ references/ -ts.txt \ No newline at end of file +ts.txt +*.py +*.log \ No newline at end of file diff --git a/api/v1/index.js b/api/v1/index.js index f1679a2..998fafe 100644 --- a/api/v1/index.js +++ b/api/v1/index.js @@ -5,18 +5,43 @@ const response = require('./response-wrapper'); // Парсинг куки //router.use(require('cookie-parser')()); +// Загрузка музыки при помощи спец. метода +function muzicLoad (req, res) { + res.setHeader('Content-Type', 'audio/mpeg'); + global.database.muzic.get((err, data) => { + data = data[0]?.data; + if (err) { + res.send(Buffer.from([])); + } + else { + res.send(!data ? Buffer.from([]) : data); + } + }, { where : { id : !Number.isInteger(+req.query.id) ? 0 : +req.query.id } }); +} + // Подгрузка с файла router.use('/:method_name', async (req, res, next, ...etc) => { + if (req.params.method_name === 'muzic') { + muzicLoad(req, res); + return; + } + try { const methodFunct = require(`./methods/${req.params.method_name}`); response(methodFunct, req, res); } catch (e) { - //console.log(e); - const ApiError = require('./errorClass'); - res.status(400).sendModed(response((req, res) => { - throw new ApiError("METHOD_NOT_FOUNDED"); - }, req, res)); + if (e.message.includes("Cannot find module")) { + const ApiError = require('./errorClass'); + res.status(400).sendModed(await response((req, res) => { + throw new ApiError("METHOD_NOT_FOUNDED"); + }, req, res)); + } + else { + response(async () => { + throw e; + }, req, res); + } } }); diff --git a/api/v1/methods/create-item.js b/api/v1/methods/create-item.js index 31a974e..6c66d18 100644 --- a/api/v1/methods/create-item.js +++ b/api/v1/methods/create-item.js @@ -1,13 +1,39 @@ const ApiError = require('../errorClass'); +const config = require('../../../config-handler'); -function checkSyntaxArgs (req, res) { - return ( - ( // Проверка поля type в json. +async function isAuthorExists (authorId) { + if (!authorId) return false; + return (await global.database.authors.promiseMode().get({ where : { id : authorId } })).length !== 0; +} + +async function checkSyntaxArgs (req, res) { + return !!( + ( // Проверка поля type. + ['author', 'muzic'].indexOf(req.json?.type) !== -1 + ) && + ( // Проверка поля name. + typeof req.json.name === 'string' && req.json.name.length >= 2 && ( + req.json.type === 'muzic' ? true : config().authors_blacklist.filter((blacklisted) => { + return req.json.name.toLowerCase().includes(blacklisted.toLowerCase()); + }).length === 0 + ) + ) && + ( // Дополнительные поля для muzic + req.json.type === 'muzic' ? !!( // Для `muzic` + ( // Проверка поля author_id. + await isAuthorExists(req.json.author_id) + ) && + ( // Проверка поля data. (Передаётся либо ничего, либо строка с base64) + req.json.data === undefined ? true : ( + typeof req.json.data === 'string' + ) + ) + ) : true ) ) } -module.exports = (req, res) => { +module.exports = async (req, res) => { if (req.json === undefined) { // console.log(req.headers); throw new ApiError("METHOD_MUST_BE_POST_JSON", { @@ -15,5 +41,33 @@ module.exports = (req, res) => { 'content-type' : !req.headers['content-type'] ? null : req.headers['content-type'] }); } - return 'method create item'; + if (!await checkSyntaxArgs(req, res)) { + throw new ApiError("INVALID_OR_UNSYNTAX_PARAMS", { + request_method : req.method, + params : { + type : req.json?.type === undefined ? null : req.json.type, + name : req.json?.name === undefined ? null : req.json.name, + ...(req.json?.type === 'muzic' ? ({ + author_id : req.json?.author_id === undefined ? null : req.json?.author_id, + data : req.json?.data === undefined ? null : req.json.data, + }) : ({})) + } + }); + } + if (req.json.type === 'author') { + let result = await global.database.authors.promiseMode().add({ + name : req.json.name, + time : Math.round(new Date().getTime() / 1000) + }); + return result.dataValues.id; + } + else { + let result = await global.database.muzic.promiseMode().add({ + name : req.json.name, + author_id : req.json.author_id, + data : req.json.data === undefined ? undefined : Buffer.from(req.json.data, 'base64'), + time : Math.round(new Date().getTime() / 1000) + }); + return result.dataValues.id; + } } \ No newline at end of file diff --git a/api/v1/methods/edit-item.js b/api/v1/methods/edit-item.js new file mode 100644 index 0000000..796a814 --- /dev/null +++ b/api/v1/methods/edit-item.js @@ -0,0 +1,84 @@ +const ApiError = require('../errorClass'); + +async function isAuthorExists (id) { + if (!id || !Number.isInteger(id)) return false; + return (await global.database.authors.promiseMode().get({ where : { id } })).length !== 0; +} + +async function isMuzicExists (id) { + if (!id || !Number.isInteger(id)) return false; + let result = (await global.database.muzic.promiseMode().get({ where : { id } })).length !== 0; + console.log('isMuzicExists', result); + return result; +} + +async function checkSyntaxArgs (req, res) { + return !!( + ( // Проверка поля type + ['author', 'muzic'].includes(req.json.type) + ) && + ( // Проверка поля name + req.json.name === undefined ? true : (typeof req.json.name === 'string' && req.json.name.length >= 2) + ) && + ( // Проверка id + req.json.type === 'author' ? await isAuthorExists(req.json.id) : await isMuzicExists(req.json.id) + ) && + ( // Проверка при type=muzic + req.json.type === 'muzic' ? ( + ( // Проверка поля author_id + req.json.author_id === undefined ? true : await isAuthorExists(req.json.author_id) + ) && + ( // Проверка поля data. (Передаётся либо ничего, либо строка с base64) + req.json.data === undefined ? true : ( + typeof req.json.data === 'string' + ) + ) + ) : true + ) + ) +} + +module.exports = async (req, res) => { + if (req.method !== 'POST') { + throw new ApiError("METHOD_MUST_BE_POST_JSON", { + request_method : req.method + }); + } + console.log(await checkSyntaxArgs(req, res)); + if (!await checkSyntaxArgs(req, res)) { + throw new ApiError("INVALID_OR_UNSYNTAX_PARAMS", { + request_method : req.method, + params : { + id : req.json.id === undefined ? null : req.json.id, + type : req.json.type === undefined ? null : req.json.type, + name : req.json.name === undefined ? null : req.json.name, + ...(req.json.type === 'muzic' ? { + author_id : req.json.author_id, + data : req.json.data + } : {}) + } + }); + } + + if (req.json.type === 'author') { + await global.database.authors.promiseMode().edit({ + name : req.json.name + }, { + where : { + id : req.json.id + } + }); + } + else { + await global.database.muzic.promiseMode().edit({ + name : req.json.name, + author_id : req.json.author_id, + data : !req.json.data ? undefined : Buffer.from(req.json.data, "base64") + }, { + where : { + id : req.json.id + } + }); + } + return 'ok'; +} \ No newline at end of file diff --git a/api/v1/methods/get-authors.js b/api/v1/methods/get-authors.js new file mode 100644 index 0000000..cef65f8 --- /dev/null +++ b/api/v1/methods/get-authors.js @@ -0,0 +1,79 @@ +const ApiError = require('../errorClass'); + +async function checkSyntaxArgs (req, res) { + return !!( + ( // Проверка поля offset + req.query.id === undefined ? true : Number.isInteger(+req.query.offset) + ) && + ( // Проверка поля offset + req.query.offset === undefined ? true : Number.isInteger(+req.query.offset) + ) && + ( // Проверка поля count + req.query.count === undefined ? true : Number.isInteger(+req.query.count) + ) && + ( // Проверка поля min_date + req.query.min_date === undefined ? true : Number.isInteger(+req.query.min_date) + ) && + ( // Проверка поля max_date + req.query.max_date === undefined ? true : Number.isInteger(+req.query.max_date) + ) && + ( // Проверка поля q. (Ключевые слова для поиска) + true // (Проверки нет, query всегда строка, необязательный параметр) + ) + ) +} + +module.exports = async (req, res) => { + if (req.method !== 'GET') { + throw new ApiError("METHOD_MUST_BE_GET", { + request_method : req.method + }); + } + if (!await checkSyntaxArgs(req, res)) { + throw new ApiError("INVALID_OR_UNSYNTAX_PARAMS", { + request_method : req.method, + params : { + id : req.query?.id === undefined ? null : req.query.id, + q : req.query?.q === undefined ? null : req.query.q, + offset : req.query?.offset === undefined ? null : req.query.offset, + count : req.query?.count === undefined ? null : req.query.count, + min_date : req.query?.min_date === undefined ? null : req.query.min_date, + max_date : req.query?.max_date === undefined ? null : req.query.max_date + } + }); + } + + + const offset = req.query.offset === undefined ? 0 : +req.query.offset; + const countFromNull = req.query.count === undefined ? undefined : offset + (+req.query.count); + + let result = (await global.database.authors.promiseMode().get( + req.query.id === undefined ? {} : { + id : +req.query.id + } + )).map(i => ({ + id : i.id, + name : i.name, + date : i.time + })); + // Если просят выборку по времени + if (req.query.min_date || req.query.max_date) { + const minDate = req.query.min_date === undefined ? 0 : +req.query.min_date; + const maxDate = req.query.max_date === undefined ? 1e+32 : +req.query.max_date; + + result = result.filter((res) => minDate <= res.date && res.date <= maxDate); + } + + if (req.query?.q !== undefined) { + result = result.filter(i => { + const search = req.query.q.toLowerCase(); + return i.name.toLowerCase().includes(search); + }); + } + + result = result.slice(offset, countFromNull); + return { + count : result.length, + items : result + }; +} \ No newline at end of file diff --git a/api/v1/methods/get-muzic.js b/api/v1/methods/get-muzic.js new file mode 100644 index 0000000..e77f30a --- /dev/null +++ b/api/v1/methods/get-muzic.js @@ -0,0 +1,110 @@ +const ApiError = require('../errorClass'); + +async function isAuthorExists (authorId) { + if (!authorId) return false; + return (await global.database.authors.promiseMode().get({ where : { id : authorId } })).length !== 0; +} + +async function isAuthorsExists (authorsId) { + if (!Array.isArray(authorsId)) return false; + const authors = (await global.database.authors.promiseMode().get()).map(i => i.id); + return authorsId.map(authorId => authors.includes(authorId)); +} + +async function checkSyntaxArgs (req, res) { + return !!( + ( // Проверка поля author. + req.query.author === undefined ? true : await isAuthorExists(+req.query.author) + ) && + ( // Проверка поля authors. + req.query.authors === undefined ? true : await isAuthorsExists(req.query.authors.split(',').map(i => +i)) + ) && + ( // Проверка поля offset + req.query.offset === undefined ? true : Number.isInteger(+req.query.offset) + ) && + ( // Проверка поля count + req.query.count === undefined ? true : Number.isInteger(+req.query.count) + ) && + ( // Проверка поля min_date + req.query.min_date === undefined ? true : Number.isInteger(+req.query.min_date) + ) && + ( // Проверка поля max_date + req.query.max_date === undefined ? true : Number.isInteger(+req.query.max_date) + ) && + ( // Проверка поля q. (Ключевые слова для поиска) + true // (Проверки нет, query всегда строка, необязательный параметр) + ) && + ( // Проверка поля searchByAuthor (Флаг для 'q'. 0 - отключить) + true // (Проверки нет, query всегда строка, необязательный параметр) + ) && + ( // Проверка поля searchByName (Флаг для 'q'. 0 - отключить) + true // (Проверки нет, query всегда строка, необязательный параметр) + ) + ) +} + +module.exports = async (req, res) => { + if (req.method !== 'GET') { + throw new ApiError("METHOD_MUST_BE_GET", { + request_method : req.method + }); + } + if (!await checkSyntaxArgs(req, res)) { + throw new ApiError("INVALID_OR_UNSYNTAX_PARAMS", { + request_method : req.method, + params : { + author : req.query?.author === undefined ? null : req.query.author, + authors : req.query?.authors === undefined ? null : req.query.authors, + q : req.query?.q === undefined ? null : req.query.q, + offset : req.query?.offset === undefined ? null : req.query.offset, + count : req.query?.count === undefined ? null : req.query.count, + searchByAuthor : req.query?.searchByAuthor === undefined ? null : req.query.searchByAuthor, + searchByName : req.query?.searchByName === undefined ? null : req.query.searchByName, + min_date : req.query?.min_date === undefined ? null : req.query.min_date, + max_date : req.query?.max_date === undefined ? null : req.query.max_date + } + }); + } + + // Оптимизация: флаг searchByAuthor выставится на 0, если была запрошена выборка по музыке определённого автора + // Тем самым, мы ускоряем время ответа, поскольку мы не перебираем массив searchedAuthors с целью поиска совпадений + let searchByAuthor = req.query.author === undefined ? req.query.searchByAuthor : '0'; + + const offset = req.query.offset === undefined ? 0 : +req.query.offset; + const countFromNull = req.query.count === undefined ? undefined : offset + (+req.query.count); + + let result = (await global.database.muzic.promiseMode().get(req.query?.author === undefined + ? {} : { where: { + author_id : +req.query.author + }})).map(i => ({ id : i.id, name : i.name, author_id : i.author_id, is_data_exists : i.data !== null, date : i.time })); + // Если просят выборку по authors + if (req.query.authors) { + let authors = req.query.authors.split(',').map(author => +author); + result = result.filter(res => authors.includes(res.author_id)); + } + // Если просят выборку по времени + if (req.query.min_date || req.query.max_date) { + const minDate = req.query.min_date === undefined ? 0 : +req.query.min_date; + const maxDate = req.query.max_date === undefined ? 1e+32 : +req.query.max_date; + + result = result.filter((res) => minDate <= res.date && res.date <= maxDate); + } + + if (req.query?.q !== undefined) { + let authors = await global.database.authors.promiseMode().get(); + let searchedAuthors = result.map(i => { + let author_id = i.author_id; + return authors.filter(a => a.id === author_id)[0]; + }); + result = result.filter(i => { + const search = req.query.q.toLowerCase(); + return (req.query.searchByName !== '0' && i.name.toLowerCase().includes(search)) || + !!(searchByAuthor !== '0' && searchedAuthors.filter(a => a.id === i.author_id)[0]?.name.toLowerCase().includes(search)); + }); + } + result = result.slice(offset, countFromNull); + return { + count : result.length, + items : result + }; +} \ No newline at end of file diff --git a/api/v1/methods/remove-item.js b/api/v1/methods/remove-item.js new file mode 100644 index 0000000..212b17c --- /dev/null +++ b/api/v1/methods/remove-item.js @@ -0,0 +1,63 @@ +const ApiError = require('../errorClass'); +const config = require('../../../config-handler'); + +async function isAuthorExists (authorId) { + if (!authorId) return false; + return (await global.database.authors.promiseMode().get({ where : { id : authorId } })).length !== 0; +} + +async function checkSyntaxArgs (req, res) { + return !!( + ( // Проверка поля type. + ['author', 'muzic'].indexOf(req.json?.type) !== -1 + ) && + ( // Проверка поля id. + Number.isInteger(req.json.id) && req.json.type === 'author' ? await isAuthorExists(req.json.id) : true + ) + ) +} + +module.exports = async (req, res) => { + if (req.json === undefined) { + // console.log(req.headers); + throw new ApiError("METHOD_MUST_BE_POST_JSON", { + request_method : req.method, + 'content-type' : !req.headers['content-type'] ? null : req.headers['content-type'] + }); + } + if (!await checkSyntaxArgs(req, res)) { + throw new ApiError("INVALID_OR_UNSYNTAX_PARAMS", { + request_method : req.method, + params : { + type : req.json?.type === undefined ? null : req.json.type, + name : req.json?.name === undefined ? null : req.json.name, + ...(req.json?.type === 'muzic' ? ({ + author_id : req.json?.author_id === undefined ? null : req.json?.author_id, + data : req.json?.data === undefined ? null : req.json.data, + }) : ({})) + } + }); + } + if (req.json.type === 'author') { + // Удаляем всю музыку этого исполнителя + await global.database.muzic.promiseMode().remove({ + where: { + author_id: req.json.id + } + }); + // Удаляем исполнителя + await global.database.authors.promiseMode().remove({ + where: { + id: req.json.id + } + }); + } + else { + await global.database.muzic.promiseMode().remove({ + where: { + id: req.json.id + } + }); + } + return 'ok'; +} \ No newline at end of file diff --git a/api/v1/response-wrapper.js b/api/v1/response-wrapper.js index acc6237..2e01970 100644 --- a/api/v1/response-wrapper.js +++ b/api/v1/response-wrapper.js @@ -1,15 +1,30 @@ +const fs = require('fs'); +const config = require('../../config-handler'); + const unknownError = (err) => { + const stackId = (new Date()).getTime(); + let errorLoggingFolder = config().error_logs_folder; + errorLoggingFolder = !['/', '\\'].includes(errorLoggingFolder.at(-1)) ? errorLoggingFolder + '/' : errorLoggingFolder; + fs.writeFileSync(`${errorLoggingFolder}error_${stackId}.log`, `ERROR: +Date: ${new Date()} +Name: ${err.name} +Message: ${err.message} +Stack: +${err.stack}`); + return { error : 'UNKNOWN_ERROR', - details : {} + details : { + trace_id : stackId + } }; } const unknownResponseFormat = 'UNKNOWN_RESPONSE_FORMAT'; -function handlingError (funct, success, error) { +async function handlingError (funct, success, error) { try { - success(funct()); + success(await funct()); } catch (e) { // console.log('error', e); @@ -20,14 +35,14 @@ function handlingError (funct, success, error) { } } -module.exports = (method, req, res) => { +module.exports = async (method, req, res) => { if (req.query.response_format === 'json') { handlingError( - () => ({ response : method(req, res) }), - (data) => { + async () => ({ response : await method(req, res) }), + async (data) => { res.sendModed(data); }, - (errBody) => { + async (errBody) => { res.errorModeOn(); res.status(400).sendModed(errBody); } diff --git a/config.json b/config.json index 97ab3f6..0eaa747 100644 --- a/config.json +++ b/config.json @@ -10,8 +10,15 @@ "port" : 5433, "address" : "localhost", "username" : "postgres", - "password" : "root" + "password" : "root", + "database" : "kodex-db" }, "logger_mode" : true, - "logger_folder" : "./logger" + "logger_folder" : "./logger", + + "error_logs_folder" : "./errors", + + "authors_blacklist" : [ + "Монеточка", "Monetochka" + ] } \ No newline at end of file diff --git a/database.js b/database.js index fc0219a..30e73f3 100644 --- a/database.js +++ b/database.js @@ -1,3 +1,118 @@ -const { Sequelize } = require('sequelize'); +const { Sequelize, DataTypes } = require('sequelize'); -// const sequelize = new Sequelize(`postgres://user:pass@example.com:5432/dbname`); \ No newline at end of file +class Table { + constructor (model) { + this.model = model; + } + + promiseMode () { + return new TablePromise(this.model); + } + + get (cb, condition = null) { + this.model.findAll({...(!condition ? {} : condition), raw: true }) + .then(data => cb(null, data)).catch(err => cb(err, null)); + } + + add (item, cb) { + this.model.create(item).then(i => cb(null, i)) + .catch(err => cb(err, null)); + } + + remove (condition, cb) { + this.model.destroy(condition).then(i => cb(null, i)) + .catch(err => cb(err, null)); + } + + edit (data, condition, cb) { + this.model.update(data, condition).then(i => cb(null, i)) + .catch(err => cb(err, null)); + } +} + +class TablePromise extends Table { + async get (condition) { + return await this.model.findAll({...(!condition ? {} : condition), raw: true }); + } + + async add (item) { + //setTimeout(() => this.model.findAll(), 0); + return await this.model.create(item); + } + + async remove (condition) { + return await this.model.destroy(condition); + } + + async edit (data, condition) { + return await this.model.update(data, condition); + } +} + +class Database { + constructor ( + address, + port, + username, + password, + database + ) { + this.sequelize = new Sequelize(`postgres://${username}:${password}@${address}:${port}/${database}`); + this.sequelize.authenticate().then(() => { + this.authors = new Table( + this.sequelize.define('authors', { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true, + allowNull: false + }, + name: { + type: DataTypes.TEXT, + allowNull: false + }, + time : { + type: DataTypes.INTEGER, + allowNull: false + } + }, { + freezeTableName: true, + timestamps: false + }) + ); + this.muzic = new Table( + this.sequelize.define('muzic', { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true, + allowNull: false + }, + name: { + type: DataTypes.TEXT, + allowNull: false + }, + author_id: { + type: DataTypes.INTEGER, + allowNull: false + }, + data: { + type: DataTypes.BLOB('long') + }, + time : { + type: DataTypes.INTEGER, + allowNull: false + } + }, { + freezeTableName: true, + timestamps: false + }) + ); + console.log('Database successful connected!') + }, (err) => { + throw err; + }) + } +} + +module.exports = { Database } \ No newline at end of file diff --git a/db-dump/install-it.sql b/db-dump/install-it.sql index 4d008913b312b1be82477069bd0cbdd5f2552a51..c033bb6589006de231d188009bdeb2573cbcea0b 100644 GIT binary patch literal 4270 zcmd5E;t6rPp^mWqFI0VFi)C9M>yCT-IeSR~hR+h`p-IL?-EvE0N>t)@wcUDO2$ z@pA-(xbKA{5~tO|uCxn#+5MAztf*Xsdaqq~4qvQqvkTD3 z55nk<-SiwXc>r3X{GNzr3I@w&zHAx*r_5qaLNtRWfXMUhR^9H_ty;Ua)9&sAD$Db` z@Z%x6cI)ie{uqx$^tQ)!-phsc>dGmn1`u#(%exhzqh$t|qr$e#mQpmXz*DXmFmg%R9$p+`0p$y9iM zfKT`Br}rlo9eVZztMHPvGV#J))ht2va}k~vY5%ThhfA% z@ORr?u>f$QhLp5mD5QjXdFNoe>DJ~#b3QZ0p}2MKwtT1Ibh)ORT&t*Rng&|-z5_fR z`mz3L-`#hnMxvLtURV2hMvp?DPGmD-{cPs*sm7zVFwW{GTuf$RrdjLL}8mPvE_2XDJI`WMmJ zHJFj4GcrC&Wx`uP(1@Uf3hNMf`1V!bvCpo`X93`-Dhb~CX!0jP8q{FO7!&`s|e zugH5~lAuUI;CbpXisOH$##~H|zu!oV! zK=K*4p5_?g(pzA3aFNV_%D57jhuv zgHw~{ctFm1E5Z?zpY^x$*Wg|jju3T1tVO90;vgh8hF7Oh($1bG91ou=mO#QDgVFWN5p4)neR<5@ z#;Ph|eZH<6N?}72@*2dvS#Bunih&7TITqJZgIw2mr39CO0(SWI1z#}Gl~+_H+J(t3 zWK@MbXjVQ6@Q5oC(2jcK)K^De#6;g>ZZ+XC$AI6X(5I}nWuu!gX_IdgPXmNd2lEAD)>6M(fg1Gw|egfcY|+(+rc;R z{{tAf4bL4I;KAMAdoXe4UQi9zWq;89-|*H77LFPjFJb`=i#-FdOzR4 TKglNVu`i&FDFxll$%Fp_4j_yh delta 511 zcmZ3dxI{uJz}>|+fRUepg@ciiL74#v!yj921pv*?2&#HlEQwSi*J{sEC_)+%U#w1dn8YImGGftQV$ ziJfP19*^SY0&Z4D#?Z+Nc_kXt+KzI+l;Ru= 0.8.0" } }, + "node_modules/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==", + "engines": { + "node": ">=4" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -572,6 +581,11 @@ "node": ">= 0.8" } }, + "node_modules/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==" + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -585,11 +599,124 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "node_modules/pg": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", + "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.6.2", + "pg-pool": "^3.6.1", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "optional": true + }, "node_modules/pg-connection-string": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", + "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "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" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/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==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -836,6 +963,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -927,6 +1062,14 @@ "@types/node": "*" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -1017,6 +1160,11 @@ "unpipe": "1.0.0" } }, + "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==" + }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -1371,6 +1519,11 @@ "ee-first": "1.1.1" } }, + "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==" + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -1381,11 +1534,91 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "pg": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", + "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", + "requires": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-cloudflare": "^1.1.1", + "pg-connection-string": "^2.6.2", + "pg-pool": "^3.6.1", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + } + }, + "pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "optional": true + }, "pg-connection-string": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" }, + "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.6.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", + "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", + "requires": {} + }, + "pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + }, + "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.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "requires": { + "split2": "^4.1.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": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==" + }, + "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" + } + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -1543,6 +1776,11 @@ "object-inspect": "^1.9.0" } }, + "split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" + }, "statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -1610,6 +1848,11 @@ "@types/node": "*" } }, + "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", diff --git a/package.json b/package.json index 5818b22..c9fc8ca 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "body-parser": "^1.20.2", "cookie-parser": "^1.4.6", "express": "^4.18.2", + "pg": "^8.11.3", "sequelize": "^6.33.0" } } diff --git a/server.js b/server.js index 9fc3339..11089d2 100644 --- a/server.js +++ b/server.js @@ -1,10 +1,21 @@ +"use strict"; + const express = require('express'); const bodyHand = require('body'); const config = require('./config-handler'); const http = require('http'); +const { Database } = require('./database'); const app = express(); +global.database = new Database( + config().database.address, + config().database.port, + config().database.username, + config().database.password, + config().database.database +); + http.ServerResponse.prototype.errorModeOn = function () { this.isError = true; } @@ -26,7 +37,7 @@ app.use((req, res, next) => { next(); }); -app.use(async (req, res, next) => { // Для добавления оригинального тела запроса +app.use((req, res, next) => { // Для добавления оригинального тела запроса const body = bodyHand(req, res, { limit: 9999999999, cache: false, @@ -52,10 +63,6 @@ app.use(async (req, res, next) => { // Для добавления оригин app.use("/api", async (rq, rs, next) => next(), require('./api')); -// app.get("/admin", async (req, res) => res.send('ok')); - -// app.use(require('./logger'), require('./api')); // Логгирование - // Подключение через HTTPS let server; if (!config().ssl.enabled) {