Compare commits
240 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 90e8c6b3c4 | |||
| 07bf05cb2c | |||
| 49d29902a8 | |||
| 32a90c2a9e | |||
| 16ed2c1517 | |||
| 8bb0f1c799 | |||
| f14fe2dd64 | |||
| 884f0ee0de | |||
| 744270f48c | |||
| c30849be3c | |||
| f295ac8b4d | |||
| 9469a8f43d | |||
| 786799ca40 | |||
| aa6238cf5a | |||
| 1ed31ee2e2 | |||
| 7d8c12977c | |||
| 81ee1d63a6 | |||
| cf1c1b3198 | |||
| bc7b1e8472 | |||
| 7319c41cc1 | |||
| 2f09fc32c0 | |||
| f85b3f54a1 | |||
| 1a68669d6d | |||
| 6345c2d414 | |||
| 87930cad75 | |||
| 3ab2232121 | |||
| 9719e25421 | |||
| 8e1f998c39 | |||
| deb1c224f8 | |||
| b2fa79898a | |||
| da2759a3c6 | |||
| f6bc696426 | |||
| da653e9b32 | |||
| 227e153bde | |||
| 12f906b9b0 | |||
| c8236d4d10 | |||
| e2006da50d | |||
| 433a7d3641 | |||
| 6b41c74b43 | |||
| cc3e7ff7c6 | |||
| a35a6bf642 | |||
| 9ecd523646 | |||
| e7f896c38e | |||
| 624ec743b1 | |||
| 553c5745ef | |||
| 3f2779ca3d | |||
| e51b962627 | |||
| f709e135b6 | |||
| 50b48aa247 | |||
| 508f2abc82 | |||
| 42ec56e578 | |||
| 92673dac6e | |||
| daf57aba35 | |||
| dee629c429 | |||
| 67f9092350 | |||
| 88691d47a5 | |||
| 0fdd9bc803 | |||
| 8452c607b4 | |||
| 4fc57c2d57 | |||
| 9f0b707a30 | |||
| 511bc351d5 | |||
| 56ee3e962c | |||
| 2781e8519d | |||
| 46575348fe | |||
| bae2ca646b | |||
| 0686c6ab00 | |||
| db04b66ce5 | |||
| c43c8a29af | |||
| aaea18abe1 | |||
| 0b6076cb61 | |||
| 3b6d02f02c | |||
| 625a0586a3 | |||
| 10d63ca586 | |||
| d2697bf9de | |||
| fa8c8843e2 | |||
| 7b59ea4b96 | |||
| 058215934e | |||
| 1d724d841f | |||
| 32db2100de | |||
| 095c77b65b | |||
| c1c07bff8f | |||
| 1206bd0e98 | |||
| 67bcd1b307 | |||
| 31ef70e433 | |||
| afb12961d2 | |||
| 3dbd40e334 | |||
| bc5d6e38c8 | |||
| 5a39143051 | |||
| 18e9571877 | |||
| a828f4c831 | |||
| 54ac12f250 | |||
| 9a6a72f605 | |||
| 03949489e8 | |||
| 8ebd735e7e | |||
| 39246da73f | |||
| bf33f60368 | |||
| 492a613769 | |||
| 2c02c3434e | |||
| a186ddd9d2 | |||
| 4b0c7a5e4e | |||
| 54cfbe3ab6 | |||
| 02015cf0b8 | |||
| 416e4d3598 | |||
| e0d9c4b0ea | |||
| 2659e3bc09 | |||
| d296167b6a | |||
| 89b0aa7fec | |||
| 787aadf444 | |||
| d67161a29b | |||
| 7f4777ead4 | |||
| 1e2147b143 | |||
| 9f0a2fbf63 | |||
| 7804851bc9 | |||
| adc50dd89e | |||
| 5378cf5ddc | |||
| a733bb605f | |||
| aaa1b5a264 | |||
| 5855cdee65 | |||
| c0d584e644 | |||
| 955f0f473e | |||
| 9ceb888124 | |||
| e902933693 | |||
| e07b47fb10 | |||
| 5bf08d9701 | |||
| 597fa1e6fa | |||
| dda3ec0ba0 | |||
| 991f08c749 | |||
| 923865cd7c | |||
| 606aee8ccd | |||
| 4a1cb27d0a | |||
| 26cd7f3a12 | |||
| f4045dbc56 | |||
| 33c2b24550 | |||
| cd86f3c8ea | |||
| 58026ebc2d | |||
| 9183275dad | |||
| 5e3a625d95 | |||
| 3297f9d2d2 | |||
| 29b8306a28 | |||
| d84746bac6 | |||
| 4eacf2ff0b | |||
| a68e0d6f61 | |||
| ddf44304c7 | |||
| 789d98f58e | |||
| 205574620d | |||
| d9bae12b31 | |||
| c951190794 | |||
| d4e1d69c3c | |||
| f93a32c07b | |||
| 8e7c152c0d | |||
| 6a64404f20 | |||
| 1a09589add | |||
| d0f9072ab5 | |||
| 011ed9f2d8 | |||
| 12332f83d9 | |||
| 8f75829948 | |||
| a7ffedb3b2 | |||
| 378d3b9747 | |||
| 5ba05409c4 | |||
| d86beef58f | |||
| 7315d67c9f | |||
| 59d79b8c7a | |||
| 3df97653a2 | |||
| 948d55e418 | |||
| 1d2c7281b1 | |||
| 35759b943c | |||
| 29da33e200 | |||
| 1d758f8126 | |||
| b663dac2ab | |||
| 485a3971e9 | |||
| 36b5d64ca6 | |||
| 8462a709bc | |||
| 20cabe8362 | |||
| 6967864361 | |||
| a6ee3840ae | |||
| 01de6139df | |||
| 6ba0924f6c | |||
| 00c75d1fd8 | |||
| 93f28fa9d5 | |||
| 0aed10eb8b | |||
| d84d687eee | |||
| d046f56832 | |||
| 0af1fbf313 | |||
| e9aaf4309e | |||
| 80fa1085d2 | |||
| 88195291fd | |||
| 39ad600d00 | |||
| c63a3aba6b | |||
| 782ecbe307 | |||
| f75bbfa048 | |||
| 3a772cc983 | |||
| 807113523e | |||
| 7df2af8611 | |||
| 10c1697b00 | |||
| 742e5d38ab | |||
| 1d3e7f8af0 | |||
| c99bacab64 | |||
| 95d7555ebc | |||
| 5854e0a23c | |||
| 81f7f32767 | |||
| c0374a7da1 | |||
| ed65e655b9 | |||
| d250e516b5 | |||
| e4f404b2c7 | |||
| 86571331f8 | |||
| 163d420af9 | |||
| 4925ea4af0 | |||
| 57b05ce348 | |||
| 427b53fcbd | |||
| 2ac7a31be6 | |||
| 4baed6409f | |||
| 2ea0ff0965 | |||
| 88b9a7edce | |||
| 538066b960 | |||
| b10dd1d75a | |||
| f743580b55 | |||
| 0688467302 | |||
| 29e972dbf2 | |||
| bd99697c5b | |||
| 1d5c431ff6 | |||
| 3736c510ff | |||
| 26c12c3a85 | |||
| 10bb08e5e6 | |||
| b50d5b6121 | |||
| 38b28752e1 | |||
| 87c51009de | |||
| a950a47b28 | |||
| 2609d10c0b | |||
| 7b4cb0f66c | |||
| 26db0e1e69 | |||
| 62e64cbd22 | |||
| 844a47830f | |||
| 2cc1e32f45 | |||
| 9890958b1e | |||
| 6dbd6d6edc | |||
| bf7a4dfd28 | |||
| f52626bda0 | |||
| 88cec4bf2b | |||
| b880def108 | |||
| bfd5dc039a |
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
dist
|
||||
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"editor.bracketPairColorization.enabled": true,
|
||||
"editor.guides.bracketPairs": true,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.tabCompletion": "onlySnippets",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.codeActionsOnSave": ["source.fixAll.eslint"],
|
||||
"eslint.validate": ["javascript", "typescript", "vue"],
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"i18n-ally.localesPaths": ["src/i18n"],
|
||||
"typescript.format.enable": true,
|
||||
"typescript.format.indentSwitchCase": false,
|
||||
"typescript.validate.enable": true,
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.1.6](https://github.com/coopenomics/monocoop/compare/v2.1.5...v2.1.6) (2024-10-30)
|
||||
|
||||
**Note:** Version bump only for package monocoop
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.1.5](https://github.com/coopenomics/monocoop/compare/v2.1.4...v2.1.5) (2024-10-28)
|
||||
|
||||
**Note:** Version bump only for package monocoop
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.1.4](https://github.com/coopenomics/monocoop/compare/v2.1.4-alpha.2...v2.1.4) (2024-10-28)
|
||||
|
||||
**Note:** Version bump only for package monocoop
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.1.3](https://github.com/coopenomics/monocoop/compare/v2.1.2-alpha.10...v2.1.3) (2024-10-26)
|
||||
|
||||
|
||||
|
||||
## [2.1.2](https://github.com/coopenomics/monocoop/compare/v2.1.1...v2.1.2) (2024-10-19)
|
||||
|
||||
**Note:** Version bump only for package monocoop
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.1.2](https://github.com/coopenomics/monocoop/compare/v2.1.1...v2.1.2) (2024-10-19)
|
||||
|
||||
**Note:** Version bump only for package monocoop
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.1.0](https://github.com/coopenomics/monocoop/compare/v2.0.10-alpha.3...v2.1.0) (2024-10-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* запрос соглашений ([9a6a72f](https://github.com/coopenomics/monocoop/commit/9a6a72f605ba52eef2ed6f18ccee6fbed287ea00))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.0.9](https://github.com/coopenomics/monocoop/compare/v2.0.8...v2.0.9) (2024-10-10)
|
||||
|
||||
**Note:** Version bump only for package monocoop
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.0.8](https://github.com/coopenomics/monocoop/compare/v2.0.7...v2.0.8) (2024-10-09)
|
||||
|
||||
**Note:** Version bump only for package monocoop
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.0.7](https://github.com/coopenomics/monocoop/compare/v2.0.6...v2.0.7) (2024-09-30)
|
||||
|
||||
**Note:** Version bump only for package monocoop
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.0.6](https://github.com/coopenomics/monocoop/compare/v2.0.5...v2.0.6) (2024-09-30)
|
||||
|
||||
**Note:** Version bump only for package monocoop
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.0.5](https://github.com/coopenomics/monocoop/compare/v2.0.5-alpha.0...v2.0.5) (2024-09-30)
|
||||
|
||||
**Note:** Version bump only for package monocoop
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.0.2](https://github.com/coopenomics/monocoop/compare/v2.0.2-alpha.1...v2.0.2) (2024-09-29)
|
||||
|
||||
**Note:** Version bump only for package monocoop
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# 2.1.0 (2024-09-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **importers:** исправлена ошибка в импорте модуля @wharfkit/contract ([bf89032](https://github.com/coopenomics/monocoop/commit/bf89032d8f66444804a2521f4eb96ffc75b0f605))
|
||||
* **terminal:** исправлен шрифт в README ([889447a](https://github.com/coopenomics/monocoop/commit/889447a93ceadb577613ddb5b1cb2ef1cc3d54b6))
|
||||
* **terminal:** исправлено описание проекта ([989b318](https://github.com/coopenomics/monocoop/commit/989b3180ded99a871e018cf26e6c493449223c01))
|
||||
* **terminal:** fix typo in README.md ([fdf9996](https://github.com/coopenomics/monocoop/commit/fdf999619d2d69e960b062fe6815f5b057c95f48))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* добавлен docker-compose.yaml ([6a46697](https://github.com/coopenomics/monocoop/commit/6a46697c9d6cc3cde14dbce8f70997c00f9850de))
|
||||
* **package:** добавлен скрипт gpt-commit для удобного коммита ([e0b5107](https://github.com/coopenomics/monocoop/commit/e0b510799bb0ac68890d572deb652beefd0651c4))
|
||||
* **terminal:** добавлена поддержка новых команд ([73e4ca2](https://github.com/coopenomics/monocoop/commit/73e4ca226acebcbea3ae59a62def99d86efb1353))
|
||||
@@ -0,0 +1,39 @@
|
||||
k# Conventional Commits
|
||||
|
||||
### Основные типы коммитов:
|
||||
|
||||
- **`feat`**: Добавление новой функциональности (feature).
|
||||
- Пример: `feat: добавлена возможность загрузки файлов`
|
||||
|
||||
- **`fix`**: Исправление бага.
|
||||
- Пример: `fix: исправлена ошибка отображения кнопки на мобильных устройствах`
|
||||
|
||||
- **`chore`**: Изменения, не влияющие на исходный код (например, обновление зависимостей или инструментария).
|
||||
- Пример: `chore: обновление зависимостей`
|
||||
|
||||
- **`docs`**: Изменения в документации.
|
||||
- Пример: `docs: обновлено руководство пользователя`
|
||||
|
||||
- **`style`**: Изменения стиля кода, не влияющие на его функциональность (форматирование, пробелы, и т.д.).
|
||||
- Пример: `style: исправлены отступы в коде`
|
||||
|
||||
- **`refactor`**: Изменения в коде, которые не исправляют баги и не добавляют новую функциональность.
|
||||
- Пример: `refactor: улучшена структура класса`
|
||||
|
||||
- **`perf`**: Изменения, направленные на улучшение производительности.
|
||||
- Пример: `perf: оптимизирована работа с массивами`
|
||||
|
||||
- **`test`**: Добавление или изменение тестов.
|
||||
- Пример: `test: добавлен тест для проверки функции отправки сообщений`
|
||||
|
||||
### Дополнительные типы коммитов:
|
||||
|
||||
- **`build`**: Изменения, связанные с процессом сборки или зависимостями.
|
||||
- Пример: `build: обновление конфигурации Webpack`
|
||||
|
||||
- **`ci`**: Изменения, касающиеся настроек непрерывной интеграции (например, Travis, Jenkins).
|
||||
- Пример: `ci: настройка Travis для автоматических сборок`
|
||||
|
||||
- **`revert`**: Откат на предыдущие изменения.
|
||||
- Пример: `revert: откат коммита e0b5107`
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
FROM node:18-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN npm install -g pnpm lerna
|
||||
RUN pnpm install
|
||||
RUN lerna run build
|
||||
|
||||
@@ -1,4 +1,18 @@
|
||||
# MONOCOOP
|
||||
|
||||
Моно-репозиторий компонент Цифрового Кооператива.
|
||||
Моно-репозиторий компонент клиента системы электронного документооборота для потребительских и производственных кооперативов.
|
||||
|
||||
## Инициализация
|
||||
```
|
||||
curl -X POST http://127.0.0.1:2998/v1/system/init \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "server-secret: SECRET" \
|
||||
-d @init-cooperative1.json
|
||||
```
|
||||
|
||||
## Лицензия
|
||||
Продукт Потребительского Кооператива "ВОСХОД" распространяется по лицензии BY-NC-SA 4.0.
|
||||
|
||||
Разрешено делиться, копировать и распространять материал на любом носителе и форме, адаптировать, делать ремиксы, видоизменять и создавать новое, опираясь на этот материал. При использовании, Вы должны обеспечить указание авторства, предоставить ссылку, и обозначить изменения, если таковые были сделаны. Если вы перерабатываете, преобразовываете материал или берёте его за основу для производного произведения, вы должны распространять переделанные вами части материала на условиях той же лицензии , в соответствии с которой распространяется оригинал. Запрещено коммерческое использование материала. Использование в коммерческих целях – это использование, в первую очередь направленное на получение коммерческого преимущества или денежного вознаграждения.
|
||||
|
||||
Юридический текст лицензии: https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.ru
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
module.exports = {
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
project: 'tsconfig.json',
|
||||
tsconfigRootDir: __dirname,
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['@typescript-eslint/eslint-plugin'],
|
||||
extends: [
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
jest: true,
|
||||
},
|
||||
ignorePatterns: ['.eslintrc.js'],
|
||||
rules: {
|
||||
'@typescript-eslint/interface-name-prefix': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
.idea/
|
||||
.vscode/
|
||||
node_modules/
|
||||
build/
|
||||
tmp/
|
||||
temp/
|
||||
dist/
|
||||
.env
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.1.6](https://github.com/coopenomics/monocoop/compare/v2.1.5...v2.1.6) (2024-10-30)
|
||||
|
||||
**Note:** Version bump only for package @coopenomics/controller-next
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.0.2](https://github.com/coopenomics/provider/compare/v0.0.2-alpha.0...v0.0.2) (2024-10-23)
|
||||
|
||||
**Note:** Version bump only for package backend
|
||||
@@ -0,0 +1,11 @@
|
||||
FROM node:18-slim AS base
|
||||
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
|
||||
RUN corepack enable pnpm \
|
||||
&& corepack prepare pnpm@latest --activate
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package.json ./
|
||||
@@ -0,0 +1,99 @@
|
||||
<p align="center">
|
||||
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
|
||||
</p>
|
||||
|
||||
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
|
||||
[circleci-url]: https://circleci.com/gh/nestjs/nest
|
||||
|
||||
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
|
||||
<p align="center">
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
|
||||
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
|
||||
<a href="https://coveralls.io/github/nestjs/nest?branch=master" target="_blank"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9" alt="Coverage" /></a>
|
||||
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
|
||||
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
|
||||
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
|
||||
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg" alt="Donate us"/></a>
|
||||
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
|
||||
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow" alt="Follow us on Twitter"></a>
|
||||
</p>
|
||||
<!--[](https://opencollective.com/nest#backer)
|
||||
[](https://opencollective.com/nest#sponsor)-->
|
||||
|
||||
## Description
|
||||
|
||||
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
|
||||
|
||||
## Project setup
|
||||
|
||||
```bash
|
||||
$ pnpm install
|
||||
```
|
||||
|
||||
## Compile and run the project
|
||||
|
||||
```bash
|
||||
# development
|
||||
$ pnpm run start
|
||||
|
||||
# watch mode
|
||||
$ pnpm run start:dev
|
||||
|
||||
# production mode
|
||||
$ pnpm run start:prod
|
||||
```
|
||||
|
||||
## Run tests
|
||||
|
||||
```bash
|
||||
# unit tests
|
||||
$ pnpm run test
|
||||
|
||||
# e2e tests
|
||||
$ pnpm run test:e2e
|
||||
|
||||
# test coverage
|
||||
$ pnpm run test:cov
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
When you're ready to deploy your NestJS application to production, there are some key steps you can take to ensure it runs as efficiently as possible. Check out the [deployment documentation](https://docs.nestjs.com/deployment) for more information.
|
||||
|
||||
If you are looking for a cloud-based platform to deploy your NestJS application, check out [Mau](https://mau.nestjs.com), our official platform for deploying NestJS applications on AWS. Mau makes deployment straightforward and fast, requiring just a few simple steps:
|
||||
|
||||
```bash
|
||||
$ pnpm install -g mau
|
||||
$ mau deploy
|
||||
```
|
||||
|
||||
With Mau, you can deploy your application in just a few clicks, allowing you to focus on building features rather than managing infrastructure.
|
||||
|
||||
## Resources
|
||||
|
||||
Check out a few resources that may come in handy when working with NestJS:
|
||||
|
||||
- Visit the [NestJS Documentation](https://docs.nestjs.com) to learn more about the framework.
|
||||
- For questions and support, please visit our [Discord channel](https://discord.gg/G7Qnnhy).
|
||||
- To dive deeper and get more hands-on experience, check out our official video [courses](https://courses.nestjs.com/).
|
||||
- Deploy your application to AWS with the help of [NestJS Mau](https://mau.nestjs.com) in just a few clicks.
|
||||
- Visualize your application graph and interact with the NestJS application in real-time using [NestJS Devtools](https://devtools.nestjs.com).
|
||||
- Need help with your project (part-time to full-time)? Check out our official [enterprise support](https://enterprise.nestjs.com).
|
||||
- To stay in the loop and get updates, follow us on [X](https://x.com/nestframework) and [LinkedIn](https://linkedin.com/company/nestjs).
|
||||
- Looking for a job, or have a job to offer? Check out our official [Jobs board](https://jobs.nestjs.com).
|
||||
|
||||
## Support
|
||||
|
||||
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
|
||||
|
||||
## Stay in touch
|
||||
|
||||
- Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec)
|
||||
- Website - [https://nestjs.com](https://nestjs.com/)
|
||||
- Twitter - [@nestframework](https://twitter.com/nestframework)
|
||||
|
||||
## License
|
||||
|
||||
Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE).
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/nest-cli",
|
||||
"collection": "@nestjs/schematics",
|
||||
"sourceRoot": "src",
|
||||
"compilerOptions": {
|
||||
"deleteOutDir": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
|
||||
"spaces": 2,
|
||||
"generator-cli": {
|
||||
"version": "7.9.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
{
|
||||
"name": "@coopenomics/controller-next",
|
||||
"version": "2.1.6",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
"license": "UNLICENSED",
|
||||
"scripts": {
|
||||
"build": "nest build",
|
||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||
"start": "node dist/main.js",
|
||||
"generate-api-client": "openapi --input swagger.json --output ./client/generated",
|
||||
"dev": "nest start --watch",
|
||||
"dev:debug": "nest start --debug --watch",
|
||||
"start:prod": "node dist/main",
|
||||
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:cov": "jest --coverage",
|
||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json",
|
||||
"typeorm": "typeorm-ts-node-commonjs",
|
||||
"migration:generate": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:generate -d ./data-source.ts",
|
||||
"migration:run": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:run -d ./data-source.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@litehex/node-vault": "^1.0.0",
|
||||
"@nestjs/bull": "^10.2.1",
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/config": "^3.2.3",
|
||||
"@nestjs/core": "^10.0.0",
|
||||
"@nestjs/platform-express": "^10.0.0",
|
||||
"@nestjs/schedule": "^4.1.1",
|
||||
"@nestjs/swagger": "^7.4.2",
|
||||
"@nestjs/typeorm": "^10.0.2",
|
||||
"@wharfkit/antelope": "^1.0.12",
|
||||
"@wharfkit/contract": "^1.1.5",
|
||||
"@wharfkit/session": "^1.4.0",
|
||||
"@wharfkit/wallet-plugin-privatekey": "^1.1.0",
|
||||
"axios": "^1.2.1",
|
||||
"bull": "^4.16.3",
|
||||
"cooptypes": "^2.1.2",
|
||||
"docxtemplater": "^3.51.1",
|
||||
"dotenv": "^16.4.5",
|
||||
"faker": "^5.1.0",
|
||||
"fs-extra": "^11.2.0",
|
||||
"glob": "^11.0.0",
|
||||
"joi": "^17.13.3",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"libreoffice-convert": "^1.6.0",
|
||||
"nextcloud-link": "^1.2.9",
|
||||
"pg": "^8.4.0",
|
||||
"pizzip": "^3.1.7",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rxjs": "^7.8.1",
|
||||
"swagger-ui-express": "^5.0.1",
|
||||
"typeorm": "0.3.20",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^10.0.0",
|
||||
"@nestjs/schematics": "^10.0.0",
|
||||
"@nestjs/testing": "^10.0.0",
|
||||
"@types/bull": "^4.10.0",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/node": "^16.11.10",
|
||||
"@types/supertest": "^6.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"eslint": "^9.0.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"jest": "^29.5.0",
|
||||
"openapi-typescript-codegen": "^0.29.0",
|
||||
"prettier": "^3.0.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"supertest": "^7.0.0",
|
||||
"ts-jest": "^29.1.0",
|
||||
"ts-loader": "^9.4.3",
|
||||
"ts-node": "10.9.1",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"typescript": "5.6.3"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
"js",
|
||||
"json",
|
||||
"ts"
|
||||
],
|
||||
"rootDir": "src",
|
||||
"testRegex": ".*\\.spec\\.ts$",
|
||||
"transform": {
|
||||
"^.+\\.(t|j)s$": "ts-jest"
|
||||
},
|
||||
"collectCoverageFrom": [
|
||||
"**/*.(t|j)s"
|
||||
],
|
||||
"coverageDirectory": "../coverage",
|
||||
"testEnvironment": "node"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import * as glob from 'glob';
|
||||
import * as path from 'path';
|
||||
import { validateEnv } from './env.validator';
|
||||
import { BullModule as NestBullModule } from '@nestjs/bull';
|
||||
|
||||
// Функция для динамического импорта модулей
|
||||
function dynamicImportModules(): any[] {
|
||||
const modules = [] as any[];
|
||||
|
||||
const modulePaths = glob.sync(
|
||||
path.join(__dirname, 'modules/*/*.module.{ts,js}'),
|
||||
);
|
||||
|
||||
modulePaths.forEach((modulePath) => {
|
||||
const module = require(modulePath);
|
||||
const moduleName = Object.keys(module)[0]; // Получаем имя экспортируемого модуля
|
||||
modules.push(module[moduleName]);
|
||||
});
|
||||
return modules;
|
||||
}
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
...dynamicImportModules(), // Динамически импортируем все найденные модули
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true, // Чтобы .env был доступен глобально
|
||||
validate: validateEnv, // Заменяем стандартную валидацию на свою
|
||||
}),
|
||||
NestBullModule.forRoot({
|
||||
redis: {
|
||||
host: process.env.REDIS_HOST,
|
||||
port: parseInt(process.env.REDIS_PORT as string),
|
||||
password: process.env.REDIS_PASSWORD,
|
||||
},
|
||||
}),
|
||||
TypeOrmModule.forRoot({
|
||||
type: 'postgres',
|
||||
host: process.env.PROVIDER_DB_HOST,
|
||||
port: Number(process.env.PROVIDER_DB_PORT),
|
||||
username: process.env.PROVIDER_DB_USERNAME,
|
||||
password: process.env.PROVIDER_DB_PASSWORD,
|
||||
database: process.env.PROVIDER_DB_DATABASE,
|
||||
entities: [path.join(__dirname, 'modules/*/entities/*.{ts,js}')],
|
||||
migrations: ['migrations/*.ts'], // Указываем путь на исходные TS файлы миграций
|
||||
synchronize: true, //поменять когда-нибудь потом
|
||||
logging: false,
|
||||
}),
|
||||
],
|
||||
controllers: [],
|
||||
providers: [],
|
||||
})
|
||||
export class AppModule {}
|
||||
@@ -0,0 +1,76 @@
|
||||
import { z } from 'zod';
|
||||
import { config } from 'dotenv';
|
||||
|
||||
// Загружаем переменные окружения
|
||||
config();
|
||||
|
||||
// Определяем схему валидации без необходимости указывать сообщения
|
||||
const envSchema = z.object({
|
||||
NODE_ENV: z
|
||||
.enum(['development', 'production', 'test'])
|
||||
.default('development'),
|
||||
PROVIDER_DB_HOST: z.string(),
|
||||
PROVIDER_DB_PORT: z
|
||||
.string()
|
||||
.transform((val) => parseInt(val, 10))
|
||||
.default('5432'),
|
||||
PROVIDER_DB_USERNAME: z.string(),
|
||||
PROVIDER_DB_PASSWORD: z.string(),
|
||||
PROVIDER_DB_DATABASE: z.string(),
|
||||
CHAIN_URL: z.string().url(),
|
||||
CHAIN_ID: z.string(),
|
||||
SEMAPHORE_API_URL: z.string().url(),
|
||||
SEMAPHORE_USERNAME: z.string(),
|
||||
SEMAPHORE_PASSWORD: z.string(),
|
||||
SEMAPHORE_PROJECT_ID: z.string().transform((val) => parseInt(val, 10)),
|
||||
SEMAPHORE_INVENTORY_ID: z.string().transform((val) => parseInt(val, 10)),
|
||||
SEMAPHORE_SSH_KEY_ID: z.string().transform((val) => parseInt(val, 10)),
|
||||
SEMAPHORE_INVENTORY_NAME: z.string(),
|
||||
SEMAPHORE_TEMPLATE_ID: z.string().transform((val) => parseInt(val, 10)),
|
||||
SERVER_IP: z.string().refine(
|
||||
(ip) => {
|
||||
const ipRegex =
|
||||
/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
||||
return ipRegex.test(ip);
|
||||
},
|
||||
{ message: 'Invalid IP address' },
|
||||
),
|
||||
SEMAPHORE_SETUP_PLAYBOOK: z.string(),
|
||||
PROVIDER_ACCOUNT: z.string(),
|
||||
PROVIDER_WIF: z.string(),
|
||||
START_TOKENS: z.string(), // если нужно можно добавить валидацию формата
|
||||
SERVER_SECRET: z.string(),
|
||||
PROVIDER_URL: z.string().url(),
|
||||
// VAULT
|
||||
VAULT_TOKEN: z.string(),
|
||||
VAULT_ENDPOINT: z.string(),
|
||||
|
||||
// NEXTCLOUD
|
||||
NEXTCLOUD_BASE_URL: z.string(),
|
||||
NEXTCLOUD_USERNAME: z.string(),
|
||||
NEXTCLOUD_PASSWORD: z.string(),
|
||||
|
||||
// REDIS
|
||||
REDIS_HOST: z.string(),
|
||||
REDIS_PORT: z.string(),
|
||||
REDIS_PASSWORD: z.string(),
|
||||
});
|
||||
|
||||
// Валидация переменных окружения с единым сообщением об отсутствии полей
|
||||
export function validateEnv() {
|
||||
const parsedEnv = envSchema.safeParse(process.env);
|
||||
|
||||
if (!parsedEnv.success) {
|
||||
const formattedErrors = parsedEnv.error.format();
|
||||
|
||||
const errorMessages = Object.keys(formattedErrors)
|
||||
.filter((key) => key !== '_errors')
|
||||
.map((key) => `${key}: параметр не установлен`)
|
||||
.join('\n');
|
||||
|
||||
console.error('❌ Ошибка конфигурации:\n', errorMessages);
|
||||
process.exit(1); // Завершаем приложение в случае ошибки
|
||||
}
|
||||
|
||||
return parsedEnv.data; // Возвращаем валидированные данные
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
||||
import { writeFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
|
||||
// Настройка Swagger
|
||||
const config = new DocumentBuilder()
|
||||
.setTitle('API Documentation')
|
||||
.setDescription('API description')
|
||||
.setVersion('1.0')
|
||||
.build();
|
||||
const document = SwaggerModule.createDocument(app, config);
|
||||
|
||||
// Создание файла swagger.json
|
||||
const swaggerFilePath = join(process.cwd(), 'swagger.json');
|
||||
writeFileSync(swaggerFilePath, JSON.stringify(document, null, 2), {
|
||||
encoding: 'utf8',
|
||||
});
|
||||
Logger.log(`Swagger JSON file generated at: ${swaggerFilePath}`, 'Swagger');
|
||||
|
||||
// Настройка Swagger UI
|
||||
SwaggerModule.setup('api-docs', app, document);
|
||||
|
||||
await app.listen(process.env.PORT ?? 4090);
|
||||
Logger.log(
|
||||
`Application started on ${process.env.PORT ?? 4090} port`,
|
||||
'System',
|
||||
);
|
||||
}
|
||||
bootstrap();
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { BlockchainService } from './blockchain.service';
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
controllers: [],
|
||||
providers: [BlockchainService],
|
||||
exports: [BlockchainService],
|
||||
})
|
||||
export class BlockchainModule {}
|
||||
@@ -0,0 +1,147 @@
|
||||
import { Action, APIClient, PrivateKey } from '@wharfkit/antelope';
|
||||
import { ContractKit, Table } from '@wharfkit/contract';
|
||||
import { Session, type TransactResult } from '@wharfkit/session';
|
||||
import { WalletPluginPrivateKey } from '@wharfkit/wallet-plugin-privatekey';
|
||||
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { SystemContract } from 'cooptypes';
|
||||
|
||||
@Injectable()
|
||||
export class BlockchainService {
|
||||
private readonly logger = new Logger(BlockchainService.name);
|
||||
|
||||
public apiClient: APIClient;
|
||||
public contractKit: ContractKit;
|
||||
public session: Session;
|
||||
|
||||
constructor() {
|
||||
this.apiClient = new APIClient({
|
||||
url: process.env.CHAIN_URL,
|
||||
});
|
||||
this.contractKit = new ContractKit({
|
||||
client: this.apiClient,
|
||||
});
|
||||
|
||||
this.session = new Session({
|
||||
actor: process.env.PROVIDER_ACCOUNT,
|
||||
permission: 'active',
|
||||
chain: {
|
||||
id: process.env.CHAIN_ID as string,
|
||||
url: process.env.CHAIN_URL as string,
|
||||
},
|
||||
walletPlugin: new WalletPluginPrivateKey(
|
||||
PrivateKey.fromString(process.env.PROVIDER_WIF as string),
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
public transact = async (
|
||||
actionOrActions: any | any[],
|
||||
broadcast = true,
|
||||
): Promise<TransactResult | undefined> => {
|
||||
if (Array.isArray(actionOrActions)) {
|
||||
return await this.sendActions(actionOrActions, broadcast);
|
||||
} else {
|
||||
return await this.sendAction(actionOrActions, broadcast);
|
||||
}
|
||||
};
|
||||
|
||||
public formActionFromAbi = async (action: any) => {
|
||||
const { abi } = (await this.apiClient.v1.chain.get_abi(action.account)) ?? {
|
||||
abi: undefined,
|
||||
};
|
||||
return Action.from(action, abi);
|
||||
};
|
||||
|
||||
public sendAction = async (action: any, broadcast: boolean) => {
|
||||
const formedAction = await this.formActionFromAbi(action);
|
||||
|
||||
return this.session.transact(
|
||||
{
|
||||
action: formedAction,
|
||||
},
|
||||
{ broadcast },
|
||||
);
|
||||
};
|
||||
|
||||
public sendActions = async (actions: any[], broadcast: boolean) => {
|
||||
const data: Action[] = [];
|
||||
|
||||
for (const action of actions) {
|
||||
const formedAction = await this.formActionFromAbi(action);
|
||||
data.push(formedAction);
|
||||
}
|
||||
|
||||
return this.session.transact(
|
||||
{
|
||||
actions: data,
|
||||
},
|
||||
{ broadcast },
|
||||
);
|
||||
};
|
||||
|
||||
public async transfer(
|
||||
from: string,
|
||||
to: string,
|
||||
quantity: string,
|
||||
memo: string,
|
||||
): Promise<void> {
|
||||
const data = {
|
||||
account: 'eosio.token',
|
||||
name: 'transfer',
|
||||
authorization: [
|
||||
{
|
||||
actor: process.env.PROVIDER_ACCOUNT as string,
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
data: {
|
||||
from,
|
||||
to,
|
||||
quantity,
|
||||
memo,
|
||||
},
|
||||
};
|
||||
|
||||
await this.transact(data);
|
||||
}
|
||||
|
||||
public async powerup(
|
||||
data: SystemContract.Actions.Powerup.IPowerup,
|
||||
): Promise<void> {
|
||||
const action = {
|
||||
account: 'eosio',
|
||||
name: SystemContract.Actions.Powerup.actionName,
|
||||
authorization: [
|
||||
{
|
||||
actor: process.env.PROVIDER_ACCOUNT as string,
|
||||
permission: 'active',
|
||||
},
|
||||
],
|
||||
data,
|
||||
};
|
||||
|
||||
await this.transact(action);
|
||||
}
|
||||
|
||||
public async getAllTableRows(
|
||||
code: string,
|
||||
scope: string,
|
||||
name: string,
|
||||
): Promise<any[]> {
|
||||
const { abi } = await this.apiClient.v1.chain.get_abi(code);
|
||||
|
||||
if (!abi) throw new Error(`ABI контракта ${code} не найден`);
|
||||
|
||||
const table = new Table({
|
||||
abi,
|
||||
account: code,
|
||||
name: name,
|
||||
client: this.apiClient,
|
||||
});
|
||||
|
||||
const rows = await table.all({ scope });
|
||||
|
||||
return JSON.parse(JSON.stringify(rows));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import {
|
||||
ApiBody,
|
||||
ApiOperation,
|
||||
ApiParam,
|
||||
ApiResponse,
|
||||
ApiTags,
|
||||
getSchemaPath,
|
||||
} from '@nestjs/swagger';
|
||||
import { Body, Controller, Get, Param, Post } from '@nestjs/common';
|
||||
import { BullService } from './bull.service';
|
||||
import { JobEntity } from './entities/job.entity';
|
||||
|
||||
@ApiTags('jobs') // Добавляет тег для группировки в Swagger UI
|
||||
@Controller('jobs') // Базовый маршрут для всех методов этого контроллера
|
||||
@Controller()
|
||||
export class BullController {
|
||||
constructor(private readonly bullService: BullService) {}
|
||||
|
||||
@ApiOperation({ summary: 'Получить все задачи' })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Возвращает массив задач',
|
||||
type: [JobEntity],
|
||||
}) // Указываем, что возвращается массив
|
||||
@Get('/all')
|
||||
async getAllJobs(): Promise<JobEntity[]> {
|
||||
return this.bullService.getAllJobs();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { BullService } from './bull.service';
|
||||
import { JobEntity } from './entities/job.entity';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { BullController } from './bull.controller';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([JobEntity])],
|
||||
controllers: [BullController],
|
||||
providers: [BullService],
|
||||
exports: [BullService],
|
||||
})
|
||||
export class BullModule {}
|
||||
@@ -0,0 +1,168 @@
|
||||
// modules/bull/bull.service.ts
|
||||
|
||||
import { Injectable, OnModuleInit, Logger } from '@nestjs/common';
|
||||
import { Queue, Job, JobId, JobOptions } from 'bull';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { JobEntity } from './entities/job.entity';
|
||||
|
||||
// Интерфейс для возврата данных после выполнения задачи
|
||||
export interface JobResult<T> {
|
||||
result: T;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class BullService implements OnModuleInit {
|
||||
private readonly logger = new Logger(BullService.name);
|
||||
private queues: Map<string, Queue> = new Map();
|
||||
|
||||
constructor(
|
||||
@InjectRepository(JobEntity)
|
||||
private readonly jobRepository: Repository<JobEntity>,
|
||||
) {}
|
||||
|
||||
onModuleInit() {
|
||||
this.logger.log('BullService initialized');
|
||||
}
|
||||
|
||||
// Регистрация очереди по её имени, если она уже не была зарегистрирована
|
||||
registerQueue(queueName: string, queue: Queue) {
|
||||
if (!this.queues.has(queueName)) {
|
||||
this.queues.set(queueName, queue);
|
||||
this.logger.log(`Очередь зарегистрирована: ${queueName}`);
|
||||
} else {
|
||||
this.logger.warn(`Очередь ${queueName} уже зарегистрирована.`);
|
||||
}
|
||||
}
|
||||
|
||||
// Получение очереди по имени
|
||||
public getQueue(queueName: string): Queue {
|
||||
const queue = this.queues.get(queueName);
|
||||
if (!queue) {
|
||||
throw new Error(`Очередь не зарегистрирована: ${queueName}`);
|
||||
}
|
||||
return queue;
|
||||
}
|
||||
|
||||
// Метод для добавления задачи в очередь с дженериком T для результата
|
||||
async addJob<T>(
|
||||
queueName: string,
|
||||
jobType: string,
|
||||
jobData: any,
|
||||
options: JobOptions = {
|
||||
attempts: 3, // 3 попытки в случае сбоя
|
||||
backoff: 1000, // задержка перед повтором в 1000 мс
|
||||
},
|
||||
): Promise<Job<JobResult<T>>> {
|
||||
this.logger.log(
|
||||
`Добавление задачи типа "${jobType}" в очередь "${queueName}" с данными: ${JSON.stringify(
|
||||
jobData,
|
||||
)}`,
|
||||
);
|
||||
const queue = this.getQueue(queueName);
|
||||
|
||||
// Создаем задачу с типом результата T
|
||||
const job = await queue.add(jobType, jobData, options);
|
||||
|
||||
// Сохраняем задачу в базе данных
|
||||
await this.saveJobToDatabase(job, queueName);
|
||||
|
||||
return job as Job<JobResult<T>>;
|
||||
}
|
||||
|
||||
// Метод для обновления прогресса задачи
|
||||
async updateJobProgress(job: Job, progress: number): Promise<void> {
|
||||
await job.progress(progress);
|
||||
this.logger.log(`Обновлен прогресс задачи ${job.id} до ${progress}%`);
|
||||
|
||||
// Обновляем запись в базе данных
|
||||
await this.saveJobToDatabase(job, job.queue.name);
|
||||
}
|
||||
|
||||
// Метод для сохранения результата задачи с дженериком T
|
||||
async saveJobResult<T>(job: Job<JobResult<T>>, result: T): Promise<void> {
|
||||
job.data.result = result; // Сохраняем результат в данных задачи
|
||||
await job.update(job.data); // Обновляем задачу с результатом
|
||||
|
||||
this.logger.log(
|
||||
`Результат задачи ${job.id} сохранен: ${JSON.stringify(result)}`,
|
||||
);
|
||||
|
||||
// Обновляем запись в базе данных
|
||||
await this.saveJobToDatabase(job, job.queue.name);
|
||||
}
|
||||
|
||||
// Метод для пометки задачи как завершенной
|
||||
async completeJob(job: Job): Promise<void> {
|
||||
this.logger.log(`Задача ${job.id} успешно завершена.`);
|
||||
await job.moveToCompleted('completed', true);
|
||||
|
||||
// Обновляем запись в базе данных
|
||||
await this.saveJobToDatabase(job, job.queue.name);
|
||||
}
|
||||
|
||||
// Метод для пометки задачи как провалившейся
|
||||
async failJob(job: Job, error: any): Promise<void> {
|
||||
this.logger.error(
|
||||
`Задача ${job.id} завершилась с ошибкой: ${error.message}`,
|
||||
);
|
||||
await job.moveToFailed({ message: error.message }, true);
|
||||
|
||||
// Обновляем запись в базе данных
|
||||
await this.saveJobToDatabase(job, job.queue.name);
|
||||
}
|
||||
|
||||
// Метод для сохранения или обновления задачи в базе данных
|
||||
private async saveJobToDatabase(job: Job, queueName: string) {
|
||||
const existingJob = await this.jobRepository.findOne({
|
||||
where: { jobId: job.id.toString() },
|
||||
});
|
||||
|
||||
const progress: number = (
|
||||
typeof job.progress === 'number' ? job.progress : 0
|
||||
) as number;
|
||||
|
||||
const jobData = {
|
||||
jobId: job.id.toString(),
|
||||
queueName,
|
||||
data: JSON.stringify(job.data),
|
||||
status: await job.getState(),
|
||||
progress,
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
if (existingJob) {
|
||||
// Обновляем существующую запись
|
||||
await this.jobRepository.update(existingJob.id, jobData);
|
||||
} else {
|
||||
// Создаем новую запись
|
||||
const jobEntity = this.jobRepository.create({
|
||||
...jobData,
|
||||
});
|
||||
await this.jobRepository.save(jobEntity);
|
||||
}
|
||||
}
|
||||
|
||||
// Получение задачи по ID
|
||||
async getJob<T>(
|
||||
queueName: string,
|
||||
jobId: JobId,
|
||||
): Promise<Job<JobResult<T>> | null> {
|
||||
const queue = this.getQueue(queueName);
|
||||
const job = await queue.getJob(jobId);
|
||||
return job as Job<JobResult<T>>;
|
||||
}
|
||||
|
||||
// Методы для извлечения задач из базы данных
|
||||
async getAllJobs(): Promise<JobEntity[]> {
|
||||
return await this.jobRepository.find();
|
||||
}
|
||||
|
||||
async getJobsByQueue(queueName: string): Promise<JobEntity[]> {
|
||||
return await this.jobRepository.find({ where: { queueName } });
|
||||
}
|
||||
|
||||
async getJobByJobId(jobId: string): Promise<JobEntity | null> {
|
||||
return await this.jobRepository.findOne({ where: { jobId } });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// entities/job.entity.ts
|
||||
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
@Entity('jobs')
|
||||
export class JobEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ unique: true })
|
||||
jobId: string;
|
||||
|
||||
@Column()
|
||||
queueName: string;
|
||||
|
||||
@Column('text')
|
||||
data: string;
|
||||
|
||||
@Column()
|
||||
status: string;
|
||||
|
||||
@Column({ type: 'float', default: 0 })
|
||||
progress: number;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn()
|
||||
updatedAt: Date;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// src/cms/cms.module.ts
|
||||
import { Module, MiddlewareConsumer, NestModule } from '@nestjs/common';
|
||||
import { CmsController } from './controllers/cms.controller';
|
||||
|
||||
@Module({
|
||||
controllers: [CmsController],
|
||||
})
|
||||
export class CmsModule {}
|
||||
@@ -0,0 +1,19 @@
|
||||
// src/cms/cms.controller.ts
|
||||
import { Controller, Get, Res, Param } from '@nestjs/common';
|
||||
import { Response } from 'express';
|
||||
import { join } from 'path';
|
||||
|
||||
@Controller('cms')
|
||||
export class CmsController {
|
||||
@Get('*') // Обрабатываем все запросы
|
||||
serveCms(@Param() params: any, @Res() res: Response) {
|
||||
const filePath = join(
|
||||
__dirname,
|
||||
'../../public/cms',
|
||||
params[0] || 'index.html',
|
||||
);
|
||||
res.sendFile(filePath); // Возвращаем запрашиваемый файл
|
||||
}
|
||||
}
|
||||
|
||||
// <iframe src="https://yourdomain.com/cms?token=YOUR_JWT_TOKEN&product_id=123"></iframe>
|
||||
@@ -0,0 +1,10 @@
|
||||
// src/modules/nextcloud/nextcloud.module.ts
|
||||
|
||||
import { Module } from '@nestjs/common';
|
||||
import { NextcloudService } from './nextcloud.service';
|
||||
|
||||
@Module({
|
||||
providers: [NextcloudService],
|
||||
exports: [NextcloudService],
|
||||
})
|
||||
export class NextcloudModule {}
|
||||
@@ -0,0 +1,221 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { NextcloudClient } from 'nextcloud-link';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
interface OcsNewUser {
|
||||
userid: string;
|
||||
password?: string;
|
||||
email?: string;
|
||||
displayName?: string;
|
||||
groups?: string[];
|
||||
subadmin?: string[];
|
||||
quota?: number;
|
||||
language?: string;
|
||||
}
|
||||
|
||||
enum OcsShareType {
|
||||
user = 0,
|
||||
group = 1,
|
||||
publicLink = 3,
|
||||
federatedCloudShare = 6,
|
||||
}
|
||||
|
||||
enum OcsSharePermissions {
|
||||
default = -1,
|
||||
read = 1,
|
||||
update = 2,
|
||||
create = 4,
|
||||
delete = 8,
|
||||
share = 16,
|
||||
all = 31,
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class NextcloudService {
|
||||
private readonly logger = new Logger(NextcloudService.name);
|
||||
private client: NextcloudClient;
|
||||
|
||||
constructor() {
|
||||
// Инициализация клиента Nextcloud
|
||||
this.client = new NextcloudClient({
|
||||
url: process.env.NEXTCLOUD_BASE_URL as string, // URL вашего Nextcloud, например 'https://your-nextcloud-instance.com'
|
||||
username: process.env.NEXTCLOUD_USERNAME, // Имя пользователя (администратор)
|
||||
password: process.env.NEXTCLOUD_PASSWORD, // Пароль или пароль приложения
|
||||
});
|
||||
}
|
||||
|
||||
// Загрузка файла в Nextcloud
|
||||
async uploadFile(
|
||||
localFilePath: string,
|
||||
remoteFilePath: string,
|
||||
): Promise<void> {
|
||||
try {
|
||||
// Чтение файла как Buffer
|
||||
const fileBuffer = fs.readFileSync(localFilePath);
|
||||
await this.client.put(remoteFilePath, fileBuffer);
|
||||
this.logger.log(`Файл загружен в Nextcloud: ${remoteFilePath}`);
|
||||
} catch (error: any) {
|
||||
this.logger.error(`Ошибка при загрузке файла: ${error.message}`);
|
||||
throw new Error(`Не удалось загрузить файл: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async touchFolder(path: string): Promise<void> {
|
||||
try {
|
||||
const share = await this.client.touchFolder(path);
|
||||
} catch (error: any) {
|
||||
this.logger.error(`Ошибка при создании папки: ${error.message}`);
|
||||
throw new Error(`Не удалось создать папку: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Получение публичной ссылки на файл
|
||||
async shareFile(remoteFilePath: string): Promise<string> {
|
||||
try {
|
||||
const share = await this.client.shares.add(
|
||||
remoteFilePath,
|
||||
OcsShareType.publicLink, // 3 соответствует публичной ссылке
|
||||
undefined,
|
||||
OcsSharePermissions.read, // 1 означает только чтение
|
||||
);
|
||||
|
||||
const shareUrl = share.url;
|
||||
|
||||
if (!shareUrl) {
|
||||
throw new Error(`Не удалось получить ссылку на файл ${remoteFilePath}`);
|
||||
} else {
|
||||
this.logger.log(`Файл расшарен по ссылке: ${shareUrl}`);
|
||||
return shareUrl;
|
||||
}
|
||||
} catch (error: any) {
|
||||
this.logger.error(`Ошибка при шаринге файла: ${error.message}`);
|
||||
throw new Error(`Не удалось расшарить файл: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Создание нового пользователя
|
||||
async createUser(newUser: OcsNewUser): Promise<void> {
|
||||
try {
|
||||
await this.client.users.add(newUser); // Передаем объект newUser
|
||||
this.logger.log(`Пользователь ${newUser.userid} успешно создан`);
|
||||
} catch (error: any) {
|
||||
this.logger.error(`Ошибка при создании пользователя: ${error.message}`);
|
||||
throw new Error(`Не удалось создать пользователя: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Добавление пользователя в группу
|
||||
async addUserToGroup(username: string, groupName: string): Promise<void> {
|
||||
try {
|
||||
await this.client.users.addToGroup(username, groupName);
|
||||
this.logger.log(
|
||||
`Пользователь ${username} добавлен в группу ${groupName}`,
|
||||
);
|
||||
} catch (error: any) {
|
||||
this.logger.error(
|
||||
`Ошибка при добавлении пользователя в группу: ${error.message}`,
|
||||
);
|
||||
throw new Error(
|
||||
`Не удалось добавить пользователя в группу: ${error.message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Создание новой группы
|
||||
async createGroup(groupName: string): Promise<void> {
|
||||
try {
|
||||
await this.client.groups.add(groupName);
|
||||
this.logger.log(`Группа ${groupName} успешно создана`);
|
||||
} catch (error: any) {
|
||||
this.logger.error(`Ошибка при создании группы: ${error.message}`);
|
||||
throw new Error(`Не удалось создать группу: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Назначение пользователя администратором группы
|
||||
async promoteUserToGroupAdmin(
|
||||
username: string,
|
||||
groupName: string,
|
||||
): Promise<void> {
|
||||
try {
|
||||
await this.client.users.addSubAdminToGroup(username, groupName);
|
||||
this.logger.log(
|
||||
`Пользователь ${username} назначен администратором группы ${groupName}`,
|
||||
);
|
||||
} catch (error: any) {
|
||||
this.logger.error(
|
||||
`Ошибка при назначении администратора группы: ${error.message}`,
|
||||
);
|
||||
throw new Error(
|
||||
`Не удалось назначить администратора группы: ${error.message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Метод для создания групповой папки с разрешениями только на чтение для всех
|
||||
async createReadOnlyGroupFolder(
|
||||
mountpoint: string,
|
||||
groupId: string,
|
||||
): Promise<void> {
|
||||
try {
|
||||
// Создаем групповую папку и получаем её ID
|
||||
const folderId = await this.client.groupfolders.addFolder(mountpoint);
|
||||
this.logger.log(`Групповая папка ${mountpoint} создана с ID ${folderId}`);
|
||||
|
||||
// Добавляем группу в папку
|
||||
await this.client.groupfolders.addGroup(folderId, groupId);
|
||||
this.logger.log(
|
||||
`Группа ${groupId} добавлена в групповую папку ${folderId}`,
|
||||
);
|
||||
|
||||
// Устанавливаем разрешения только на чтение для группы
|
||||
await this.client.groupfolders.setPermissions(
|
||||
folderId,
|
||||
groupId,
|
||||
OcsSharePermissions.read,
|
||||
);
|
||||
this.logger.log(
|
||||
`Установлены разрешения только на чтение для группы ${groupId} в папке ${folderId}`,
|
||||
);
|
||||
} catch (error: any) {
|
||||
this.logger.error(
|
||||
`Ошибка при создании групповой папки: ${error.message}`,
|
||||
);
|
||||
throw new Error(`Не удалось создать групповую папку: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Метод для создания групповой папки с полными разрешениями для всех участников
|
||||
async createFullAccessGroupFolder(
|
||||
mountpoint: string,
|
||||
groupId: string,
|
||||
): Promise<void> {
|
||||
try {
|
||||
// Создаем групповую папку и получаем её ID
|
||||
const folderId = await this.client.groupfolders.addFolder(mountpoint);
|
||||
this.logger.log(`Групповая папка ${mountpoint} создана с ID ${folderId}`);
|
||||
|
||||
// Добавляем группу в папку
|
||||
await this.client.groupfolders.addGroup(folderId, groupId);
|
||||
this.logger.log(
|
||||
`Группа ${groupId} добавлена в групповую папку ${folderId}`,
|
||||
);
|
||||
|
||||
// Устанавливаем полные разрешения для группы
|
||||
await this.client.groupfolders.setPermissions(
|
||||
folderId,
|
||||
groupId,
|
||||
OcsSharePermissions.all,
|
||||
);
|
||||
this.logger.log(
|
||||
`Установлены полные разрешения для группы ${groupId} в папке ${folderId}`,
|
||||
);
|
||||
} catch (error: any) {
|
||||
this.logger.error(
|
||||
`Ошибка при создании групповой папки: ${error.message}`,
|
||||
);
|
||||
throw new Error(`Не удалось создать групповую папку: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// src/modules/notificator/notificator.module.ts
|
||||
|
||||
import { Module } from '@nestjs/common';
|
||||
import { BullModule as NestBullModule } from '@nestjs/bull';
|
||||
import { NotificatorService } from './notificator.service';
|
||||
import { BullModule } from '../bull/bull.module';
|
||||
import { BullService } from '../bull/bull.service';
|
||||
import { InjectQueue } from '@nestjs/bull';
|
||||
import { Queue } from 'bull';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
// Регистрируем очередь 'notificationQueue' на уровне модуля
|
||||
NestBullModule.registerQueue({
|
||||
name: 'notificationQueue',
|
||||
}),
|
||||
BullModule,
|
||||
],
|
||||
providers: [NotificatorService],
|
||||
})
|
||||
export class NotificatorModule {
|
||||
constructor(
|
||||
private readonly bullService: BullService,
|
||||
@InjectQueue('notificationQueue') private readonly notificationQueue: Queue,
|
||||
) {
|
||||
// Регистрируем очередь в BullService с именем и объектом очереди
|
||||
this.bullService.registerQueue('notificationQueue', this.notificationQueue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// modules/notificator/notificator.service.ts
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { BullService } from '../bull/bull.service';
|
||||
import { JobOptions } from 'bull';
|
||||
|
||||
@Injectable()
|
||||
export class NotificatorService {
|
||||
constructor(private readonly bullService: BullService) {}
|
||||
|
||||
async notifyUser(
|
||||
userId: string,
|
||||
sequential: boolean = false, // Для последовательного или параллельного выполнения
|
||||
): Promise<string> {
|
||||
const queueName = 'notificationQueue';
|
||||
const jobData = {
|
||||
taskName: 'User Notification',
|
||||
userId,
|
||||
sequential,
|
||||
};
|
||||
|
||||
// Добавляем задачу в очередь
|
||||
const job = await this.bullService.addJob(
|
||||
queueName,
|
||||
'email', // Тип задачи, которую будет обрабатывать процессор
|
||||
jobData,
|
||||
{},
|
||||
);
|
||||
|
||||
// Возвращаем ID задачи для отслеживания прогресса
|
||||
return job.id as string;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// modules/notificator/processors/email.processor.ts
|
||||
|
||||
import { Processor, Process } from '@nestjs/bull';
|
||||
import { Job } from 'bull';
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { BullService } from '../../bull/bull.service';
|
||||
|
||||
@Processor('notificationQueue')
|
||||
export class EmailProcessor {
|
||||
private readonly logger = new Logger(EmailProcessor.name);
|
||||
|
||||
constructor(private readonly bullService: BullService) {}
|
||||
|
||||
@Process('email')
|
||||
async handleEmailTask(job: Job<any>): Promise<void> {
|
||||
this.logger.log(`Processing email task with id ${job.id}`);
|
||||
|
||||
try {
|
||||
// Реализация отправки email
|
||||
await this.sendEmail(job.data);
|
||||
|
||||
// Обновление прогресса задачи до 100%
|
||||
await this.bullService.updateJobProgress(job, 100);
|
||||
|
||||
// Пометка задачи как завершенной
|
||||
await this.bullService.completeJob(job);
|
||||
} catch (error: any) {
|
||||
this.logger.error(`Error in email task ${job.id}: ${error.message}`);
|
||||
|
||||
// Пометка задачи как провалившейся
|
||||
await this.bullService.failJob(job, error);
|
||||
}
|
||||
}
|
||||
|
||||
private async sendEmail(data: any): Promise<void> {
|
||||
// Логика отправки email
|
||||
await new Promise((resolve) => setTimeout(resolve, 500)); // Заглушка для симуляции отправки
|
||||
// Если нужно симулировать ошибку, можно выбросить исключение:
|
||||
// throw new Error('Email sending failed');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"openapi": "3.0.0",
|
||||
"paths": {
|
||||
"/jobs/all": {
|
||||
"get": {
|
||||
"operationId": "BullController_getAllJobs",
|
||||
"summary": "Получить все задачи",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Возвращает массив задач",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/JobEntity"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"jobs"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/cms/*": {
|
||||
"get": {
|
||||
"operationId": "CmsController_serveCms",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"info": {
|
||||
"title": "API Documentation",
|
||||
"description": "API description",
|
||||
"version": "1.0",
|
||||
"contact": {}
|
||||
},
|
||||
"tags": [],
|
||||
"servers": [],
|
||||
"components": {
|
||||
"schemas": {
|
||||
"JobEntity": {
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"moduleFileExtensions": ["js", "json", "ts"],
|
||||
"rootDir": "../src/",
|
||||
"testEnvironment": "node",
|
||||
"testRegex": ".test.ts$",
|
||||
"transform": {
|
||||
"^.+\\.(t|j)s$": "ts-jest"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es2020", // Более новый target для Node.js
|
||||
"lib": ["es2020"],
|
||||
"esModuleInterop": true,
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"strictPropertyInitialization": false // Опция для инъекции зависимостей
|
||||
},
|
||||
"exclude": ["dist", "build"]
|
||||
}
|
||||
@@ -3,6 +3,74 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.1.3](https://github.com/copenomics/cooparser/compare/v2.1.2-alpha.10...v2.1.3) (2024-10-26)
|
||||
|
||||
|
||||
|
||||
## [2.1.2](https://github.com/copenomics/cooparser/compare/v2.1.1...v2.1.2) (2024-10-19)
|
||||
|
||||
**Note:** Version bump only for package cooparser-ts
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.1.2](https://github.com/copenomics/cooparser/compare/v2.1.1...v2.1.2) (2024-10-19)
|
||||
|
||||
**Note:** Version bump only for package cooparser-ts
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.1.0](https://github.com/copenomics/cooparser/compare/v2.0.10-alpha.3...v2.1.0) (2024-10-13)
|
||||
|
||||
**Note:** Version bump only for package cooparser-ts
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.0.9](https://github.com/copenomics/cooparser/compare/v2.0.8...v2.0.9) (2024-10-10)
|
||||
|
||||
**Note:** Version bump only for package cooparser-ts
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.0.8](https://github.com/copenomics/cooparser/compare/v2.0.7...v2.0.8) (2024-10-09)
|
||||
|
||||
**Note:** Version bump only for package cooparser-ts
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.0.2](https://github.com/copenomics/cooparser/compare/v2.0.2-alpha.1...v2.0.2) (2024-09-29)
|
||||
|
||||
**Note:** Version bump only for package cooparser-ts
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.0.20](https://github.com/copenomics/cooparser/compare/cooparser-ts@1.0.20-alpha.0...cooparser-ts@1.0.20) (2024-09-29)
|
||||
|
||||
**Note:** Version bump only for package cooparser-ts
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.0.18](https://github.com/copenomics/cooparser/compare/cooparser-ts@1.0.17...cooparser-ts@1.0.18) (2024-08-25)
|
||||
|
||||
**Note:** Version bump only for package cooparser-ts
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.0.17](https://github.com/copenomics/cooparser/compare/cooparser-ts@1.0.17-alpha.2...cooparser-ts@1.0.17) (2024-07-25)
|
||||
|
||||
**Note:** Version bump only for package cooparser-ts
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "pkg-placeholder",
|
||||
"version": "1.0.17",
|
||||
"version": "2.1.3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pkg-placeholder",
|
||||
"version": "1.0.17",
|
||||
"version": "2.1.3",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^2.16.0",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "cooparser-ts",
|
||||
"type": "module",
|
||||
"version": "1.0.17",
|
||||
"private": true,
|
||||
"version": "2.1.3",
|
||||
"private": false,
|
||||
"packageManager": "pnpm@9.0.6",
|
||||
"description": "",
|
||||
"author": "Alex Ant <dacom.dark.sun@gmail.com>",
|
||||
@@ -82,5 +82,6 @@
|
||||
"unbuild": "^2.0.0",
|
||||
"vite": "^5.2.10",
|
||||
"vitest": "^1.5.2"
|
||||
}
|
||||
},
|
||||
"gitHead": "7b59ea4b96991ed06abdc92e6d7835632845e3a5"
|
||||
}
|
||||
|
||||
Generated
+19
-225
@@ -69,9 +69,6 @@ importers:
|
||||
esno:
|
||||
specifier: ^4.7.0
|
||||
version: 4.7.0
|
||||
lint-staged:
|
||||
specifier: ^15.2.2
|
||||
version: 15.2.2
|
||||
nodemon:
|
||||
specifier: ^3.1.4
|
||||
version: 3.1.4
|
||||
@@ -1039,10 +1036,6 @@ packages:
|
||||
ajv@6.12.6:
|
||||
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
|
||||
|
||||
ansi-escapes@6.2.1:
|
||||
resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==}
|
||||
engines: {node: '>=14.16'}
|
||||
|
||||
ansi-regex@5.0.1:
|
||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -1233,14 +1226,6 @@ packages:
|
||||
resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
cli-cursor@4.0.0:
|
||||
resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
|
||||
cli-truncate@4.0.0:
|
||||
resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
cliui@8.0.1:
|
||||
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -1271,9 +1256,6 @@ packages:
|
||||
colord@2.9.3:
|
||||
resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
|
||||
|
||||
colorette@2.0.20:
|
||||
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
|
||||
|
||||
colorspace@1.1.4:
|
||||
resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==}
|
||||
|
||||
@@ -1281,10 +1263,6 @@ packages:
|
||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
commander@11.1.0:
|
||||
resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
commander@7.2.0:
|
||||
resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -1506,9 +1484,6 @@ packages:
|
||||
elliptic@6.5.4:
|
||||
resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==}
|
||||
|
||||
emoji-regex@10.3.0:
|
||||
resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==}
|
||||
|
||||
emoji-regex@8.0.0:
|
||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||
|
||||
@@ -1770,9 +1745,6 @@ packages:
|
||||
eventemitter3@4.0.7:
|
||||
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
|
||||
|
||||
eventemitter3@5.0.1:
|
||||
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
|
||||
|
||||
execa@8.0.1:
|
||||
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
|
||||
engines: {node: '>=16.17'}
|
||||
@@ -1893,10 +1865,6 @@ packages:
|
||||
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
|
||||
engines: {node: 6.* || 8.* || >= 10.*}
|
||||
|
||||
get-east-asian-width@1.2.0:
|
||||
resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
get-func-name@2.0.2:
|
||||
resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
|
||||
|
||||
@@ -2083,14 +2051,6 @@ packages:
|
||||
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
is-fullwidth-code-point@4.0.0:
|
||||
resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
is-fullwidth-code-point@5.0.0:
|
||||
resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
is-glob@4.0.3:
|
||||
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -2200,10 +2160,6 @@ packages:
|
||||
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
||||
lilconfig@3.0.0:
|
||||
resolution: {integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
lilconfig@3.1.1:
|
||||
resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==}
|
||||
engines: {node: '>=14'}
|
||||
@@ -2211,15 +2167,6 @@ packages:
|
||||
lines-and-columns@1.2.4:
|
||||
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||
|
||||
lint-staged@15.2.2:
|
||||
resolution: {integrity: sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==}
|
||||
engines: {node: '>=18.12.0'}
|
||||
hasBin: true
|
||||
|
||||
listr2@8.0.1:
|
||||
resolution: {integrity: sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
local-pkg@0.5.0:
|
||||
resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==}
|
||||
engines: {node: '>=14'}
|
||||
@@ -2257,10 +2204,6 @@ packages:
|
||||
lodash@4.17.21:
|
||||
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||
|
||||
log-update@6.0.0:
|
||||
resolution: {integrity: sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
logform@2.6.0:
|
||||
resolution: {integrity: sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
@@ -2346,10 +2289,6 @@ packages:
|
||||
engines: {node: '>=4'}
|
||||
hasBin: true
|
||||
|
||||
mimic-fn@2.1.0:
|
||||
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
mimic-fn@4.0.0:
|
||||
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -2546,10 +2485,6 @@ packages:
|
||||
one-time@1.0.0:
|
||||
resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==}
|
||||
|
||||
onetime@5.1.2:
|
||||
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
onetime@6.0.0:
|
||||
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -2682,11 +2617,6 @@ packages:
|
||||
resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
pidtree@0.6.0:
|
||||
resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==}
|
||||
engines: {node: '>=0.10'}
|
||||
hasBin: true
|
||||
|
||||
pkg-types@1.1.0:
|
||||
resolution: {integrity: sha512-/RpmvKdxKf8uILTtoOhAgf30wYbP2Qw+L9p3Rvshx1JZVX+XQNZQFjlbmGHEGIm4CkVPlSn+NXmIM8+9oWQaSA==}
|
||||
|
||||
@@ -2976,17 +2906,10 @@ packages:
|
||||
resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
|
||||
hasBin: true
|
||||
|
||||
restore-cursor@4.0.0:
|
||||
resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
|
||||
reusify@1.0.4:
|
||||
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
|
||||
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
|
||||
|
||||
rfdc@1.3.1:
|
||||
resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==}
|
||||
|
||||
rimraf@3.0.2:
|
||||
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
|
||||
hasBin: true
|
||||
@@ -3085,9 +3008,6 @@ packages:
|
||||
siginfo@2.0.0:
|
||||
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
|
||||
|
||||
signal-exit@3.0.7:
|
||||
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
|
||||
|
||||
signal-exit@4.1.0:
|
||||
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
|
||||
engines: {node: '>=14'}
|
||||
@@ -3118,14 +3038,6 @@ packages:
|
||||
resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==}
|
||||
engines: {node: '>=14.16'}
|
||||
|
||||
slice-ansi@5.0.0:
|
||||
resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
slice-ansi@7.1.0:
|
||||
resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
source-map-js@1.2.0:
|
||||
resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -3179,10 +3091,6 @@ packages:
|
||||
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
string-width@7.1.0:
|
||||
resolution: {integrity: sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
string_decoder@1.3.0:
|
||||
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
|
||||
|
||||
@@ -3558,10 +3466,6 @@ packages:
|
||||
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
wrap-ansi@9.0.0:
|
||||
resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
wrappy@1.0.2:
|
||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||
|
||||
@@ -3595,10 +3499,6 @@ packages:
|
||||
resolution: {integrity: sha512-pEwzfsKbTrB8G3xc/sN7aw1v6A6c/pKxLAkjclnAyo5g5qOh6eL9WGu0o3cSDQZKrTNk4KL4lQSwZW+nBkANEg==}
|
||||
engines: {node: ^14.17.0 || >=16.0.0}
|
||||
|
||||
yaml@2.3.4:
|
||||
resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
yaml@2.4.2:
|
||||
resolution: {integrity: sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==}
|
||||
engines: {node: '>= 14'}
|
||||
@@ -3703,7 +3603,7 @@ snapshots:
|
||||
'@babel/traverse': 7.24.1
|
||||
'@babel/types': 7.24.0
|
||||
convert-source-map: 2.0.0
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
gensync: 1.0.0-beta.2
|
||||
json5: 2.2.3
|
||||
semver: 6.3.1
|
||||
@@ -3804,7 +3704,7 @@ snapshots:
|
||||
'@babel/helper-split-export-declaration': 7.22.6
|
||||
'@babel/parser': 7.24.4
|
||||
'@babel/types': 7.24.0
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
globals: 11.12.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -4013,7 +3913,7 @@ snapshots:
|
||||
'@eslint/eslintrc@2.1.4':
|
||||
dependencies:
|
||||
ajv: 6.12.6
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
espree: 9.6.1
|
||||
globals: 13.24.0
|
||||
ignore: 5.3.1
|
||||
@@ -4029,7 +3929,7 @@ snapshots:
|
||||
'@humanwhocodes/config-array@0.11.14':
|
||||
dependencies:
|
||||
'@humanwhocodes/object-schema': 2.0.3
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
minimatch: 3.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -4348,7 +4248,7 @@ snapshots:
|
||||
'@typescript-eslint/type-utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@typescript-eslint/utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@typescript-eslint/visitor-keys': 7.7.1
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
eslint: 8.57.0
|
||||
graphemer: 1.4.0
|
||||
ignore: 5.3.1
|
||||
@@ -4366,7 +4266,7 @@ snapshots:
|
||||
'@typescript-eslint/types': 7.7.1
|
||||
'@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5)
|
||||
'@typescript-eslint/visitor-keys': 7.7.1
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
eslint: 8.57.0
|
||||
optionalDependencies:
|
||||
typescript: 5.4.5
|
||||
@@ -4387,7 +4287,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5)
|
||||
'@typescript-eslint/utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
eslint: 8.57.0
|
||||
ts-api-utils: 1.3.0(typescript@5.4.5)
|
||||
optionalDependencies:
|
||||
@@ -4403,7 +4303,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 6.21.0
|
||||
'@typescript-eslint/visitor-keys': 6.21.0
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
minimatch: 9.0.3
|
||||
@@ -4418,7 +4318,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 7.7.1
|
||||
'@typescript-eslint/visitor-keys': 7.7.1
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
minimatch: 9.0.4
|
||||
@@ -4550,8 +4450,6 @@ snapshots:
|
||||
json-schema-traverse: 0.4.1
|
||||
uri-js: 4.4.1
|
||||
|
||||
ansi-escapes@6.2.1: {}
|
||||
|
||||
ansi-regex@5.0.1: {}
|
||||
|
||||
ansi-regex@6.0.1: {}
|
||||
@@ -4762,15 +4660,6 @@ snapshots:
|
||||
dependencies:
|
||||
escape-string-regexp: 1.0.5
|
||||
|
||||
cli-cursor@4.0.0:
|
||||
dependencies:
|
||||
restore-cursor: 4.0.0
|
||||
|
||||
cli-truncate@4.0.0:
|
||||
dependencies:
|
||||
slice-ansi: 5.0.0
|
||||
string-width: 7.1.0
|
||||
|
||||
cliui@8.0.1:
|
||||
dependencies:
|
||||
string-width: 4.2.3
|
||||
@@ -4803,8 +4692,6 @@ snapshots:
|
||||
|
||||
colord@2.9.3: {}
|
||||
|
||||
colorette@2.0.20: {}
|
||||
|
||||
colorspace@1.1.4:
|
||||
dependencies:
|
||||
color: 3.2.1
|
||||
@@ -4814,8 +4701,6 @@ snapshots:
|
||||
dependencies:
|
||||
delayed-stream: 1.0.0
|
||||
|
||||
commander@11.1.0: {}
|
||||
|
||||
commander@7.2.0: {}
|
||||
|
||||
comment-parser@1.4.1: {}
|
||||
@@ -4952,10 +4837,6 @@ snapshots:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
|
||||
debug@4.3.4:
|
||||
dependencies:
|
||||
ms: 2.1.2
|
||||
|
||||
debug@4.3.4(supports-color@5.5.0):
|
||||
dependencies:
|
||||
ms: 2.1.2
|
||||
@@ -5040,8 +4921,6 @@ snapshots:
|
||||
minimalistic-assert: 1.0.1
|
||||
minimalistic-crypto-utils: 1.0.1
|
||||
|
||||
emoji-regex@10.3.0: {}
|
||||
|
||||
emoji-regex@8.0.0: {}
|
||||
|
||||
emoji-regex@9.2.2: {}
|
||||
@@ -5185,7 +5064,7 @@ snapshots:
|
||||
eslint-plugin-import-x@0.5.0(eslint@8.57.0)(typescript@5.4.5):
|
||||
dependencies:
|
||||
'@typescript-eslint/utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5)
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
doctrine: 3.0.0
|
||||
eslint: 8.57.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
@@ -5202,7 +5081,7 @@ snapshots:
|
||||
'@es-joy/jsdoccomment': 0.42.0
|
||||
are-docs-informative: 0.0.2
|
||||
comment-parser: 1.4.1
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
escape-string-regexp: 4.0.0
|
||||
eslint: 8.57.0
|
||||
esquery: 1.5.0
|
||||
@@ -5258,7 +5137,7 @@ snapshots:
|
||||
|
||||
eslint-plugin-toml@0.11.0(eslint@8.57.0):
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
eslint: 8.57.0
|
||||
eslint-compat-utils: 0.5.0(eslint@8.57.0)
|
||||
lodash: 4.17.21
|
||||
@@ -5322,7 +5201,7 @@ snapshots:
|
||||
|
||||
eslint-plugin-yml@1.14.0(eslint@8.57.0):
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
eslint: 8.57.0
|
||||
eslint-compat-utils: 0.5.0(eslint@8.57.0)
|
||||
lodash: 4.17.21
|
||||
@@ -5358,7 +5237,7 @@ snapshots:
|
||||
ajv: 6.12.6
|
||||
chalk: 4.1.2
|
||||
cross-spawn: 7.0.3
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
doctrine: 3.0.0
|
||||
escape-string-regexp: 4.0.0
|
||||
eslint-scope: 7.2.2
|
||||
@@ -5420,8 +5299,6 @@ snapshots:
|
||||
|
||||
eventemitter3@4.0.7: {}
|
||||
|
||||
eventemitter3@5.0.1: {}
|
||||
|
||||
execa@8.0.1:
|
||||
dependencies:
|
||||
cross-spawn: 7.0.3
|
||||
@@ -5587,8 +5464,6 @@ snapshots:
|
||||
|
||||
get-caller-file@2.0.5: {}
|
||||
|
||||
get-east-asian-width@1.2.0: {}
|
||||
|
||||
get-func-name@2.0.2: {}
|
||||
|
||||
get-intrinsic@1.2.4:
|
||||
@@ -5760,7 +5635,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@ioredis/commands': 1.2.0
|
||||
cluster-key-slot: 1.1.2
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
denque: 2.1.0
|
||||
lodash.defaults: 4.2.0
|
||||
lodash.isarguments: 3.1.0
|
||||
@@ -5801,12 +5676,6 @@ snapshots:
|
||||
|
||||
is-fullwidth-code-point@3.0.0: {}
|
||||
|
||||
is-fullwidth-code-point@4.0.0: {}
|
||||
|
||||
is-fullwidth-code-point@5.0.0:
|
||||
dependencies:
|
||||
get-east-asian-width: 1.2.0
|
||||
|
||||
is-glob@4.0.3:
|
||||
dependencies:
|
||||
is-extglob: 2.1.1
|
||||
@@ -5891,36 +5760,10 @@ snapshots:
|
||||
prelude-ls: 1.2.1
|
||||
type-check: 0.4.0
|
||||
|
||||
lilconfig@3.0.0: {}
|
||||
|
||||
lilconfig@3.1.1: {}
|
||||
|
||||
lines-and-columns@1.2.4: {}
|
||||
|
||||
lint-staged@15.2.2:
|
||||
dependencies:
|
||||
chalk: 5.3.0
|
||||
commander: 11.1.0
|
||||
debug: 4.3.4
|
||||
execa: 8.0.1
|
||||
lilconfig: 3.0.0
|
||||
listr2: 8.0.1
|
||||
micromatch: 4.0.5
|
||||
pidtree: 0.6.0
|
||||
string-argv: 0.3.2
|
||||
yaml: 2.3.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
listr2@8.0.1:
|
||||
dependencies:
|
||||
cli-truncate: 4.0.0
|
||||
colorette: 2.0.20
|
||||
eventemitter3: 5.0.1
|
||||
log-update: 6.0.0
|
||||
rfdc: 1.3.1
|
||||
wrap-ansi: 9.0.0
|
||||
|
||||
local-pkg@0.5.0:
|
||||
dependencies:
|
||||
mlly: 1.6.1
|
||||
@@ -5952,14 +5795,6 @@ snapshots:
|
||||
|
||||
lodash@4.17.21: {}
|
||||
|
||||
log-update@6.0.0:
|
||||
dependencies:
|
||||
ansi-escapes: 6.2.1
|
||||
cli-cursor: 4.0.0
|
||||
slice-ansi: 7.1.0
|
||||
strip-ansi: 7.1.0
|
||||
wrap-ansi: 9.0.0
|
||||
|
||||
logform@2.6.0:
|
||||
dependencies:
|
||||
'@colors/colors': 1.6.0
|
||||
@@ -6023,7 +5858,7 @@ snapshots:
|
||||
|
||||
micromark@2.11.4:
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
parse-entities: 2.0.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -6041,8 +5876,6 @@ snapshots:
|
||||
|
||||
mime@1.6.0: {}
|
||||
|
||||
mimic-fn@2.1.0: {}
|
||||
|
||||
mimic-fn@4.0.0: {}
|
||||
|
||||
min-indent@1.0.1: {}
|
||||
@@ -6210,10 +6043,6 @@ snapshots:
|
||||
dependencies:
|
||||
fn.name: 1.1.0
|
||||
|
||||
onetime@5.1.2:
|
||||
dependencies:
|
||||
mimic-fn: 2.1.0
|
||||
|
||||
onetime@6.0.0:
|
||||
dependencies:
|
||||
mimic-fn: 4.0.0
|
||||
@@ -6329,8 +6158,6 @@ snapshots:
|
||||
|
||||
picomatch@4.0.2: {}
|
||||
|
||||
pidtree@0.6.0: {}
|
||||
|
||||
pkg-types@1.1.0:
|
||||
dependencies:
|
||||
confbox: 0.1.7
|
||||
@@ -6601,15 +6428,8 @@ snapshots:
|
||||
path-parse: 1.0.7
|
||||
supports-preserve-symlinks-flag: 1.0.0
|
||||
|
||||
restore-cursor@4.0.0:
|
||||
dependencies:
|
||||
onetime: 5.1.2
|
||||
signal-exit: 3.0.7
|
||||
|
||||
reusify@1.0.4: {}
|
||||
|
||||
rfdc@1.3.1: {}
|
||||
|
||||
rimraf@3.0.2:
|
||||
dependencies:
|
||||
glob: 7.2.3
|
||||
@@ -6742,8 +6562,6 @@ snapshots:
|
||||
|
||||
siginfo@2.0.0: {}
|
||||
|
||||
signal-exit@3.0.7: {}
|
||||
|
||||
signal-exit@4.1.0: {}
|
||||
|
||||
simple-git-hooks@2.11.1: {}
|
||||
@@ -6764,16 +6582,6 @@ snapshots:
|
||||
|
||||
slash@5.1.0: {}
|
||||
|
||||
slice-ansi@5.0.0:
|
||||
dependencies:
|
||||
ansi-styles: 6.2.1
|
||||
is-fullwidth-code-point: 4.0.0
|
||||
|
||||
slice-ansi@7.1.0:
|
||||
dependencies:
|
||||
ansi-styles: 6.2.1
|
||||
is-fullwidth-code-point: 5.0.0
|
||||
|
||||
source-map-js@1.2.0: {}
|
||||
|
||||
sparse-bitfield@3.0.3:
|
||||
@@ -6825,12 +6633,6 @@ snapshots:
|
||||
emoji-regex: 9.2.2
|
||||
strip-ansi: 7.1.0
|
||||
|
||||
string-width@7.1.0:
|
||||
dependencies:
|
||||
emoji-regex: 10.3.0
|
||||
get-east-asian-width: 1.2.0
|
||||
strip-ansi: 7.1.0
|
||||
|
||||
string_decoder@1.3.0:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
@@ -7087,7 +6889,7 @@ snapshots:
|
||||
vite-node@1.5.2(@types/node@20.12.7):
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
pathe: 1.1.2
|
||||
picocolors: 1.0.0
|
||||
vite: 5.2.10(@types/node@20.12.7)
|
||||
@@ -7119,7 +6921,7 @@ snapshots:
|
||||
'@vitest/utils': 1.5.2
|
||||
acorn-walk: 8.3.2
|
||||
chai: 4.4.1
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
execa: 8.0.1
|
||||
local-pkg: 0.5.0
|
||||
magic-string: 0.30.10
|
||||
@@ -7149,7 +6951,7 @@ snapshots:
|
||||
|
||||
vue-eslint-parser@9.4.2(eslint@8.57.0):
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
debug: 4.3.4(supports-color@5.5.0)
|
||||
eslint: 8.57.0
|
||||
eslint-scope: 7.2.2
|
||||
eslint-visitor-keys: 3.4.3
|
||||
@@ -7219,12 +7021,6 @@ snapshots:
|
||||
string-width: 5.1.2
|
||||
strip-ansi: 7.1.0
|
||||
|
||||
wrap-ansi@9.0.0:
|
||||
dependencies:
|
||||
ansi-styles: 6.2.1
|
||||
string-width: 7.1.0
|
||||
strip-ansi: 7.1.0
|
||||
|
||||
wrappy@1.0.2: {}
|
||||
|
||||
ws@7.5.9: {}
|
||||
@@ -7243,8 +7039,6 @@ snapshots:
|
||||
lodash: 4.17.21
|
||||
yaml: 2.4.2
|
||||
|
||||
yaml@2.3.4: {}
|
||||
|
||||
yaml@2.4.2: {}
|
||||
|
||||
yargs-parser@21.1.1: {}
|
||||
|
||||
@@ -15,10 +15,9 @@ export async function BlockParser(db: Database, reader: EosioShipReaderResolved)
|
||||
})
|
||||
|
||||
blocks$.subscribe(async (block: IBlock) => {
|
||||
// console.log('new block: ', block)
|
||||
// process.stdout.write('\r') // Возврат каретки в начало строки
|
||||
// process.stdout.write(`Блок: ${block.block_num}`) // Ваш текст
|
||||
|
||||
db.updateCurrentBlock(block.last_irreversible_block_num)
|
||||
db.updateCurrentBlock(block.block_num)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ export class Database {
|
||||
private sync: Collection | undefined
|
||||
|
||||
constructor() {
|
||||
console.log('mongo2: ', mongoUri)
|
||||
this.client = new MongoClient(mongoUri)
|
||||
}
|
||||
|
||||
@@ -52,18 +51,15 @@ export class Database {
|
||||
|
||||
const pipeline = [
|
||||
{ $match: filter },
|
||||
{ $sort: { block_num: -1, _id: -1 } },
|
||||
{ $sort: { block_num: -1 } }, // Сортировка по primary_key и block_num
|
||||
{ $group: { _id: '$primary_key', doc: { $first: '$$ROOT' } } },
|
||||
// { $match: { 'doc.present': true } },
|
||||
{ $replaceRoot: { newRoot: '$doc' } },
|
||||
{ $sort: { block_num: -1 } },
|
||||
{ $skip: (page - 1) * limit }, // Применяется внутри пайплайна
|
||||
{ $limit: limit }, // Применяется внутри пайплайна
|
||||
]
|
||||
|
||||
const [result] = await Promise.all([
|
||||
this.deltas.aggregate(pipeline)
|
||||
.skip((page - 1) * limit)
|
||||
.limit(limit)
|
||||
.toArray(),
|
||||
])
|
||||
const result = await this.deltas.aggregate(pipeline).toArray()
|
||||
|
||||
return {
|
||||
results: result as IDelta[],
|
||||
@@ -80,9 +76,10 @@ export class Database {
|
||||
|
||||
const result = await this.actions.aggregate([
|
||||
{ $match: query },
|
||||
{ $sort: { block_num: -1, _id: -1 } },
|
||||
{ $sort: { block_num: -1 } }, // Сортировка по primary_key и block_num
|
||||
{ $group: { _id: '$global_sequence', doc: { $first: '$$ROOT' } } },
|
||||
{ $replaceRoot: { newRoot: '$doc' } },
|
||||
{ $sort: { block_num: -1 } },
|
||||
{ $skip: (page - 1) * limit },
|
||||
{ $limit: limit },
|
||||
]).toArray()
|
||||
|
||||
@@ -11,7 +11,6 @@ function getEnvVar(key: string): string {
|
||||
return envVar
|
||||
}
|
||||
export const node_env = getEnvVar('NODE_ENV')
|
||||
console.log('ENV: ', node_env)
|
||||
export const eosioApi = getEnvVar('API')
|
||||
export const shipApi = getEnvVar('SHIP')
|
||||
export const mongoUri = `${getEnvVar('MONGO_EXPLORER_URI')}${node_env === 'test' ? '-test' : ''}`
|
||||
@@ -55,6 +54,7 @@ export const subsribedActions: IActionConfig[] = [
|
||||
{ code: 'soviet', action: 'joincoopdec' },
|
||||
|
||||
{ code: 'soviet', action: 'updateboard', notify: true },
|
||||
{ code: 'soviet', action: 'createboard', notify: true },
|
||||
]
|
||||
|
||||
// --------------------------
|
||||
|
||||
Vendored
BIN
Binary file not shown.
@@ -5,11 +5,7 @@
|
||||
"browser": true,
|
||||
"es2021": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"],
|
||||
"plugins": ["@typescript-eslint", "prettier"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
@@ -18,7 +14,7 @@
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"rules": {
|
||||
"no-console": "warn",
|
||||
"no-console": "off",
|
||||
"func-names": "off",
|
||||
"no-underscore-dangle": "off",
|
||||
"consistent-return": "off",
|
||||
|
||||
@@ -12,4 +12,7 @@ yarn-error.log
|
||||
coverage
|
||||
|
||||
.env-mixed
|
||||
.env-local
|
||||
.env-local
|
||||
|
||||
logs
|
||||
logs/*
|
||||
|
||||
+4
-1
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"subcode"
|
||||
]
|
||||
],
|
||||
"editor.formatOnSave": true,
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,138 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.1.6](https://github.com/hagopj13/node-express-boilerplate/compare/v2.1.5...v2.1.6) (2024-10-30)
|
||||
|
||||
**Note:** Version bump only for package @coopenomics/controller
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.1.5](https://github.com/hagopj13/node-express-boilerplate/compare/v2.1.4...v2.1.5) (2024-10-28)
|
||||
|
||||
**Note:** Version bump only for package @coopenomics/controller
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.1.4](https://github.com/hagopj13/node-express-boilerplate/compare/v2.1.4-alpha.2...v2.1.4) (2024-10-28)
|
||||
|
||||
**Note:** Version bump only for package @coopenomics/controller
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.1.3](https://github.com/hagopj13/node-express-boilerplate/compare/v2.1.2-alpha.10...v2.1.3) (2024-10-26)
|
||||
|
||||
|
||||
|
||||
## [2.1.2](https://github.com/hagopj13/node-express-boilerplate/compare/v2.1.1...v2.1.2) (2024-10-19)
|
||||
|
||||
**Note:** Version bump only for package @coopenomics/controller
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.1.2](https://github.com/hagopj13/node-express-boilerplate/compare/v2.1.1...v2.1.2) (2024-10-19)
|
||||
|
||||
**Note:** Version bump only for package coopback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.1.0](https://github.com/hagopj13/node-express-boilerplate/compare/v2.0.10-alpha.3...v2.1.0) (2024-10-13)
|
||||
|
||||
**Note:** Version bump only for package coopback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.0.8](https://github.com/hagopj13/node-express-boilerplate/compare/v2.0.7...v2.0.8) (2024-10-09)
|
||||
|
||||
**Note:** Version bump only for package coopback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.0.7](https://github.com/hagopj13/node-express-boilerplate/compare/v2.0.6...v2.0.7) (2024-09-30)
|
||||
|
||||
**Note:** Version bump only for package coopback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.0.6](https://github.com/hagopj13/node-express-boilerplate/compare/v2.0.5...v2.0.6) (2024-09-30)
|
||||
|
||||
**Note:** Version bump only for package coopback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.0.5](https://github.com/hagopj13/node-express-boilerplate/compare/v2.0.5-alpha.0...v2.0.5) (2024-09-30)
|
||||
|
||||
**Note:** Version bump only for package coopback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [2.0.2](https://github.com/hagopj13/node-express-boilerplate/compare/v2.0.2-alpha.1...v2.0.2) (2024-09-29)
|
||||
|
||||
**Note:** Version bump only for package coopback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.7.38](https://github.com/hagopj13/node-express-boilerplate/compare/coopback@1.7.38-alpha.3...coopback@1.7.38) (2024-09-29)
|
||||
|
||||
**Note:** Version bump only for package coopback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.7.34](https://github.com/hagopj13/node-express-boilerplate/compare/coopback@1.7.33...coopback@1.7.34) (2024-08-25)
|
||||
|
||||
**Note:** Version bump only for package coopback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.7.33](https://github.com/hagopj13/node-express-boilerplate/compare/coopback@1.7.32...coopback@1.7.33) (2024-08-25)
|
||||
|
||||
**Note:** Version bump only for package coopback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.7.32](https://github.com/hagopj13/node-express-boilerplate/compare/coopback@1.7.31...coopback@1.7.32) (2024-08-25)
|
||||
|
||||
**Note:** Version bump only for package coopback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.7.31](https://github.com/hagopj13/node-express-boilerplate/compare/coopback@1.7.31-alpha.1...coopback@1.7.31) (2024-08-25)
|
||||
|
||||
**Note:** Version bump only for package coopback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.7.30](https://github.com/hagopj13/node-express-boilerplate/compare/coopback@1.7.29...coopback@1.7.30) (2024-08-13)
|
||||
|
||||
**Note:** Version bump only for package coopback
|
||||
|
||||
@@ -1,47 +1,39 @@
|
||||
# Базовый образ Node.js на Alpine
|
||||
FROM node:alpine AS base
|
||||
|
||||
# ENV PNPM_HOME="/pnpm"
|
||||
# ENV PATH="$PNPM_HOME:$PATH"
|
||||
|
||||
# Включение pnpm
|
||||
RUN corepack enable pnpm \
|
||||
&& corepack prepare pnpm@latest --activate
|
||||
|
||||
|
||||
# Устанавливаем рабочую директорию
|
||||
WORKDIR /app
|
||||
|
||||
# Копируем package.json
|
||||
COPY package.json ./
|
||||
|
||||
# Install dependencies for Puppeteer
|
||||
# Установка системных зависимостей для WeasyPrint и создание виртуального окружения
|
||||
RUN apk add --no-cache \
|
||||
chromium \
|
||||
nss \
|
||||
freetype \
|
||||
freetype-dev \
|
||||
harfbuzz \
|
||||
ca-certificates \
|
||||
ttf-freefont \
|
||||
&& apk add --no-cache --virtual .build-deps \
|
||||
curl \
|
||||
python3 \
|
||||
py3-pip \
|
||||
gcc \
|
||||
musl-dev \
|
||||
python3-dev \
|
||||
pango \
|
||||
zlib-dev \
|
||||
jpeg-dev \
|
||||
openjpeg-dev \
|
||||
g++ \
|
||||
libffi-dev \
|
||||
harfbuzz-subset \
|
||||
&& python3 -m venv /venv \
|
||||
&& /venv/bin/pip install WeasyPrint==62.3 \
|
||||
&& rm -rf /var/cache/*
|
||||
|
||||
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
|
||||
# Установка пути к виртуальному окружению в PATH
|
||||
ENV PATH="/venv/bin:$PATH"
|
||||
|
||||
# RUN mkdir -p /usr/src/node-app && chown -R node:node /usr/src/node-app
|
||||
# Проверка наличия команды weasyprint
|
||||
RUN weasyprint --version
|
||||
|
||||
# WORKDIR /usr/src/node-app
|
||||
|
||||
# COPY package.json pnpm-lock.yaml ./
|
||||
|
||||
# USER node
|
||||
|
||||
# FROM base AS prod-deps
|
||||
# RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile
|
||||
|
||||
# FROM base AS build
|
||||
# RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
|
||||
|
||||
# COPY --chown=node:node . .
|
||||
|
||||
# EXPOSE 3000
|
||||
|
||||
# CMD ["npx", "ts-node", "src/index.ts"]
|
||||
# CMD для запуска weasyprint
|
||||
# CMD ["weasyprint", "input.html", "output.pdf"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# COOPERATIVE CONTROLLER
|
||||
# COOPERATIVE CONTROLLER.
|
||||
|
||||
[](https://travis-ci.org/hagopj13/node-express-boilerplate)
|
||||
[](https://coveralls.io/github/hagopj13/node-express-boilerplate?branch=master)
|
||||
@@ -8,6 +8,7 @@ A boilerplate/starter project for quickly building RESTful APIs using Node.js, E
|
||||
|
||||
By running a single command, you will get a production-ready Node.js app installed and fully configured on your machine. The app comes with many built-in features, such as authentication using JWT, request validation, unit and integration tests, continuous integration, docker support, API documentation, pagination, etc. For more details, check the features list below.
|
||||
|
||||
|
||||
## Quick Start
|
||||
|
||||
To create a project, simply run:
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "create-nodejs-express-app",
|
||||
"version": "1.7.30",
|
||||
"version": "2.1.6",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "create-nodejs-express-app",
|
||||
"version": "1.7.30",
|
||||
"version": "2.1.6",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@a2seven/yoo-checkout": "^1.1.4",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "coopback",
|
||||
"version": "1.7.30",
|
||||
"name": "@coopenomics/controller",
|
||||
"version": "2.1.6",
|
||||
"description": "",
|
||||
"private": true,
|
||||
"private": false,
|
||||
"bin": "bin/createNodejsApp.js",
|
||||
"main": "src/index.ts",
|
||||
"repository": "https://github.com/hagopj13/node-express-boilerplate.git",
|
||||
@@ -12,6 +12,9 @@
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"deploy-testnet": "git checkout testnet && git merge main && git push origin testnet && git checkout main",
|
||||
"deploy-production": "git checkout production && git merge testnet && git push origin production && git checkout main",
|
||||
@@ -80,17 +83,23 @@
|
||||
"faker": "^5.1.0",
|
||||
"helmet": "^4.1.0",
|
||||
"html-pdf-node": "^1.0.8",
|
||||
"http-proxy-middleware": "^3.0.3",
|
||||
"http-status": "^1.4.0",
|
||||
"ioredis": "^5.4.1",
|
||||
"ip": "^2.0.1",
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"jest": "^29.7.0",
|
||||
"joi": "^17.13.1",
|
||||
"joi-to-json": "^4.3.0",
|
||||
"joi-to-typescript": "^4.13.0",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"jspdf": "^2.5.1",
|
||||
"lodash": "^4.17.21",
|
||||
"moment": "^2.24.0",
|
||||
"mongoose": "^8.5.2",
|
||||
"mongoose-sequence": "^6.0.1",
|
||||
"morgan": "^1.9.1",
|
||||
"node-cron": "^3.0.3",
|
||||
"nodemailer": "^6.3.1",
|
||||
"nunjucks": "^3.2.4",
|
||||
"passport": "^0.4.0",
|
||||
@@ -100,11 +109,14 @@
|
||||
"socket.io-client": "^4.7.5",
|
||||
"swagger-jsdoc": "^6.0.8",
|
||||
"swagger-ui-express": "^4.1.6",
|
||||
"threads": "^1.7.0",
|
||||
"ts-jest": "^29.1.3",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsd": "^0.31.0",
|
||||
"tsoa": "^6.4.0",
|
||||
"validator": "^13.0.0",
|
||||
"winston": "^3.2.1",
|
||||
"winston-daily-rotate-file": "^5.0.0",
|
||||
"xss-clean": "^0.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -17,12 +17,11 @@ const [username] = args;
|
||||
async function createServiceUser(username: string) {
|
||||
try {
|
||||
await mongoose.connect(config.mongoose.url, config.mongoose.options);
|
||||
|
||||
const user = await userService.createServiceUser(username);
|
||||
const token = await tokenService.generateServiceAccessToken(user);
|
||||
logger.log('token:', token.access.token);
|
||||
console.log('token:', token.access.token);
|
||||
} catch (e: any) {
|
||||
logger.log('Ошибка: ', e.message);
|
||||
logger.error('Ошибка: ', e.message);
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
|
||||
@@ -15,15 +15,10 @@ async function init() {
|
||||
|
||||
await mongoose.connect(config.mongoose.url, config.mongoose.options);
|
||||
const wif = '5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3';
|
||||
const password = await crypto.createHash('sha256').update(wif).digest('hex');
|
||||
const hashed_password = await hash(password, 8);
|
||||
|
||||
console.log('password: ', hashed_password);
|
||||
|
||||
await userService.createUser({
|
||||
username: 'ant',
|
||||
email: 'dacom.dark.sun@gmail.com',
|
||||
password,
|
||||
public_key: 'EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV',
|
||||
role: 'user',
|
||||
type: 'individual',
|
||||
@@ -46,7 +41,6 @@ async function init() {
|
||||
const voskhod = await userService.createUser({
|
||||
username: 'voskhod',
|
||||
email: 'chairman.voskhod@gmail.com',
|
||||
password,
|
||||
public_key: 'EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV',
|
||||
role: 'user',
|
||||
type: 'organization',
|
||||
|
||||
Vendored
BIN
Binary file not shown.
@@ -14,14 +14,6 @@ import routes from './routes/v1/index';
|
||||
import { errorConverter, errorHandler } from './middlewares/error';
|
||||
import ApiError from './utils/ApiError';
|
||||
|
||||
// import { connectGenerator } from './services/data.service';
|
||||
// Подключите генератор
|
||||
// connectGenerator()
|
||||
// .then(() => {})
|
||||
// .catch((error) => {
|
||||
// console.error('Failed to connect generator:', error);
|
||||
// });
|
||||
|
||||
const app = express();
|
||||
|
||||
if (config.env !== 'test') {
|
||||
|
||||
@@ -8,8 +8,7 @@ const envVarsSchema = Joi.object()
|
||||
.keys({
|
||||
NODE_ENV: Joi.string().valid('production', 'development', 'test').required(),
|
||||
BASE_URL: Joi.string().required(),
|
||||
SERVICE_USERNAME: Joi.string().required(),
|
||||
SERVICE_WIF: Joi.string().required(),
|
||||
SERVER_SECRET: Joi.string().required(),
|
||||
PORT: Joi.number().default(3000),
|
||||
MONGODB_URL: Joi.string().required().description('Mongo DB url'),
|
||||
JWT_SECRET: Joi.string().required().description('JWT secret key'),
|
||||
@@ -31,6 +30,7 @@ const envVarsSchema = Joi.object()
|
||||
EMAIL_FROM: Joi.string().description('the from field in the emails sent by the app'),
|
||||
|
||||
COOPNAME: Joi.string().description('имя аккаунта кооператива'),
|
||||
GRAPHQL_SERVICE: Joi.string().description('адрес сервиса GRAPHQL').default('http://localhost:4090'),
|
||||
})
|
||||
.unknown();
|
||||
|
||||
@@ -44,8 +44,7 @@ export default {
|
||||
env: envVars.NODE_ENV,
|
||||
base_url: envVars.BASE_URL,
|
||||
port: envVars.PORT,
|
||||
service_wif: envVars.SERVICE_WIF,
|
||||
service_username: envVars.SERVICE_USERNAME,
|
||||
server_secret: envVars.SERVER_SECRET,
|
||||
mongoose: {
|
||||
url: envVars.MONGODB_URL + (envVars.NODE_ENV === 'test' ? '-test' : ''),
|
||||
options: {
|
||||
@@ -74,4 +73,5 @@ export default {
|
||||
from: envVars.EMAIL_FROM,
|
||||
},
|
||||
coopname: envVars.COOPNAME,
|
||||
graphql_service: envVars.GRAPHQL_SERVICE,
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import winston from 'winston';
|
||||
import DailyRotateFile from 'winston-daily-rotate-file';
|
||||
import config from './config';
|
||||
|
||||
const enumerateErrorFormat = winston.format((info) => {
|
||||
@@ -11,14 +12,34 @@ const enumerateErrorFormat = winston.format((info) => {
|
||||
const logger = winston.createLogger({
|
||||
level: config.env === 'development' ? 'debug' : 'info',
|
||||
format: winston.format.combine(
|
||||
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
|
||||
enumerateErrorFormat(),
|
||||
config.env === 'development' ? winston.format.colorize() : winston.format.uncolorize(),
|
||||
winston.format.colorize(),
|
||||
winston.format.splat(),
|
||||
winston.format.printf(({ level, message }) => `${level}: ${message}`)
|
||||
winston.format.printf(({ timestamp, level, message, ...meta }) => {
|
||||
return `${timestamp} ${level}: ${message}${Object.keys(meta).length ? ` - ${JSON.stringify(meta)}` : ''}`;
|
||||
})
|
||||
),
|
||||
transports: [
|
||||
new DailyRotateFile({
|
||||
filename: 'logs/application-%DATE%.log',
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
zippedArchive: true,
|
||||
maxSize: '20m',
|
||||
maxFiles: '30d',
|
||||
level: 'info',
|
||||
}),
|
||||
new DailyRotateFile({
|
||||
filename: 'logs/error-%DATE%.log',
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
zippedArchive: true,
|
||||
maxSize: '20m',
|
||||
maxFiles: '30d',
|
||||
level: 'error',
|
||||
}),
|
||||
new winston.transports.Console({
|
||||
stderrLevels: ['error'],
|
||||
level: 'info',
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import morgan from 'morgan'
|
||||
import config from './config'
|
||||
import logger from './logger'
|
||||
import morgan from 'morgan';
|
||||
import config from './config';
|
||||
import logger from './logger';
|
||||
|
||||
morgan.token('message', (req, res) => res.locals.errorMessage || '');
|
||||
|
||||
@@ -21,4 +21,4 @@ const errorHandler = morgan(errorResponseFormat, {
|
||||
export default {
|
||||
successHandler,
|
||||
errorHandler,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import {Strategy as JwtStrategy, ExtractJwt } from 'passport-jwt'
|
||||
import config from './config'
|
||||
import { Strategy as JwtStrategy, ExtractJwt } from 'passport-jwt';
|
||||
import config from './config';
|
||||
import { tokenTypes } from './tokens';
|
||||
import { User } from '../models';
|
||||
|
||||
|
||||
const jwtOptions = {
|
||||
secretOrKey: config.jwt.secret,
|
||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||
@@ -14,7 +13,7 @@ const jwtVerify = async (payload, done) => {
|
||||
if (payload.type !== tokenTypes.ACCESS) {
|
||||
throw new Error('Invalid token type');
|
||||
}
|
||||
const user = await User.findOne({_id: payload.sub});
|
||||
const user = await User.findOne({ _id: payload.sub });
|
||||
if (!user) {
|
||||
return done(null, false);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,34 @@
|
||||
const user = [
|
||||
'getSelf',
|
||||
'initialPayment',
|
||||
'getMyDocuments',
|
||||
'getMyOrders',
|
||||
'sendVerificationEmail',
|
||||
'manageMyMethods',
|
||||
'createDeposit',
|
||||
'joinCooperative',
|
||||
'getVars',
|
||||
'readGraph',
|
||||
];
|
||||
|
||||
const member = [
|
||||
...user,
|
||||
'getUsers',
|
||||
'manageUsers',
|
||||
'loadAgenda',
|
||||
'loadStaff',
|
||||
'getDocuments',
|
||||
'loadInfo',
|
||||
'manageOrders',
|
||||
'regenerateDocument',
|
||||
];
|
||||
|
||||
const chairman = [...user, ...member, 'addUser', 'setVars', 'manageSettings', 'setWif', 'setPlugin'];
|
||||
|
||||
const allRoles = {
|
||||
user: [''],
|
||||
service: ['addUser', 'sendNotification'],
|
||||
chairman: ['addUser', 'getUsers', 'manageUsers', 'loadAgenda', 'loadStaff', 'getDocuments', 'loadInfo'],
|
||||
member: ['getUsers', 'manageUsers', 'loadAgenda', 'loadStaff', 'getDocuments', 'loadInfo'],
|
||||
user,
|
||||
member,
|
||||
chairman,
|
||||
};
|
||||
|
||||
export const roles = Object.keys(allRoles);
|
||||
|
||||
@@ -18,7 +18,7 @@ export const loadAgenda = catchAsync(async (req: Request, res: Response) => {
|
||||
const { coopname } = req.query;
|
||||
const agenda = await coopService.loadAgenda(coopname as string);
|
||||
|
||||
const complexAgenda: Cooperative.Documents.IComplexAgenda[] = [];
|
||||
const complexAgenda: Cooperative.Document.IComplexAgenda[] = [];
|
||||
|
||||
for (const { action, table } of agenda) {
|
||||
const documents = await documentService.buildComplexDocument(action);
|
||||
|
||||
@@ -14,8 +14,8 @@ export const getDocuments = catchAsync(async (req: RGetDocuments, res) => {
|
||||
const filter = req.query?.filter;
|
||||
const limit = req.query?.limit as number;
|
||||
const page = req.query?.page as number;
|
||||
|
||||
const documents = await documentService.queryDocuments(filter, page, limit);
|
||||
const type = req.query?.type as string;
|
||||
const documents = await documentService.queryDocuments(type, filter, page, limit);
|
||||
|
||||
res.status(httpStatus.OK).send(documents);
|
||||
});
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
export * as authController from './auth.controller';
|
||||
export * as userController from './user.controller';
|
||||
export * as documentController from './document.controller';
|
||||
export * as paymentController from './payment.controller';
|
||||
export * as orderController from './order.controller';
|
||||
export * as coopController from './coop.controller';
|
||||
export * as notifyController from './notify.controller';
|
||||
export * as monoController from './mono.controller';
|
||||
export * as systemController from './system.controller';
|
||||
export * as participantController from './participant.controller';
|
||||
export * as methodController from './method.controller';
|
||||
export * as settingController from './setting.controller';
|
||||
export * as pluginController from './plugin.controller';
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import http from 'http-status';
|
||||
import catchAsync from '../utils/catchAsync';
|
||||
import { methodService } from '../services';
|
||||
import { IGetResponse } from '../types/common';
|
||||
import ApiError from '../utils/ApiError';
|
||||
import httpStatus from 'http-status';
|
||||
import { Cooperative } from 'cooptypes';
|
||||
import { getUserByUsername } from '../services/user.service';
|
||||
import type { RDeletePaymentMethod, RGetListPaymentMethods, RSavePaymentMethod } from '../types';
|
||||
|
||||
export const listPaymentMethods = catchAsync(async (req: RGetListPaymentMethods, res) => {
|
||||
const filter = req.params?.username ? { username: req.params.username } : {};
|
||||
|
||||
const methods: IGetResponse<any> = await methodService.listPaymentMethods({ ...filter });
|
||||
|
||||
res.status(httpStatus.OK).send(methods);
|
||||
});
|
||||
|
||||
export const addPaymentMethod = catchAsync(async (req: RSavePaymentMethod, res) => {
|
||||
if (req.params?.username != req.body.username)
|
||||
throw new ApiError(httpStatus.BAD_REQUEST, 'username в params и body должны совпадать');
|
||||
|
||||
const user = await getUserByUsername(req.body.username);
|
||||
|
||||
const method = req.body as any;
|
||||
|
||||
if (method.method_type === 'sbp' && !method.data.phone)
|
||||
throw new ApiError(httpStatus.BAD_REQUEST, 'Не указан телефон для метода СБП');
|
||||
|
||||
if (method.method_type === 'bank_transfer' && !method.data.account_number)
|
||||
throw new ApiError(httpStatus.BAD_REQUEST, 'Не верно указаны реквизиты для банковского платежа');
|
||||
|
||||
const paymentData: Cooperative.Payments.IPaymentData = {
|
||||
username: req.body.username,
|
||||
method_id: req.body.method_id,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
user_type: user.type as any,
|
||||
method_type: req.body.method_type,
|
||||
is_default: false,
|
||||
data: req.body.data,
|
||||
};
|
||||
|
||||
await methodService.savePaymentMethod(paymentData);
|
||||
|
||||
res.status(httpStatus.OK).send();
|
||||
});
|
||||
|
||||
export const deletePaymentMethod = catchAsync(async (req: RDeletePaymentMethod, res) => {
|
||||
await methodService.deletePaymentMethod({
|
||||
username: req.params?.username,
|
||||
method_id: req.body.method_id,
|
||||
});
|
||||
|
||||
res.status(httpStatus.OK).send();
|
||||
});
|
||||
@@ -1,18 +0,0 @@
|
||||
import httpStatus from 'http-status';
|
||||
import { getMonoStatus } from '../services/mono.service';
|
||||
import { getBlockchainInfo } from '../services/blockchain.service';
|
||||
import { IHealthResponse } from '../types';
|
||||
import { Request, Response } from 'express';
|
||||
import catchAsync from '../utils/catchAsync';
|
||||
|
||||
export const getHealth = catchAsync(async (req: Request, res: Response) => {
|
||||
const status = await getMonoStatus();
|
||||
const blockchain = await getBlockchainInfo();
|
||||
|
||||
const result: IHealthResponse = {
|
||||
status,
|
||||
blockchain,
|
||||
};
|
||||
|
||||
res.status(httpStatus.OK).send(result);
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
import http from 'http-status';
|
||||
import catchAsync from '../utils/catchAsync';
|
||||
import { orderService } from '../services';
|
||||
import { ICreateDeposit, ICreateInitialPayment } from '../types';
|
||||
import { Request, Response } from 'express';
|
||||
import httpStatus from 'http-status';
|
||||
import pick from '../utils/pick';
|
||||
import logger from '../config/logger';
|
||||
import { getProvider } from '../services/payment.service';
|
||||
|
||||
export const catchIPN = catchAsync(async (req: Request, res: Response) => {
|
||||
const providerName = req.params.provider;
|
||||
logger.info(`Recieve new IPN for provider ${providerName}`, { body: req.body, source: 'catchIPN' });
|
||||
|
||||
const provider = getProvider(providerName);
|
||||
|
||||
// Обрабатываем IPN данные
|
||||
await provider.handleIPN(req.body);
|
||||
res.status(200).send();
|
||||
});
|
||||
|
||||
export const createDeposit = catchAsync(async (req: any, res: Response) => {
|
||||
const username = req.user.username;
|
||||
|
||||
const result = await orderService.createDeposit(username, req.body as ICreateDeposit);
|
||||
res.status(http.CREATED).send(result);
|
||||
});
|
||||
|
||||
export const createInitialPayment = catchAsync(async (req: any, res: Response) => {
|
||||
const username = req.user.username;
|
||||
const result = await orderService.createInitialOrder(username);
|
||||
res.status(http.CREATED).send(result);
|
||||
});
|
||||
|
||||
export const getOrders = catchAsync(async (req: Request, res: Response) => {
|
||||
const filter = pick(req.query, ['username', 'id', 'order_num', 'status']);
|
||||
const options = pick(req.query, ['sortBy', 'limit', 'page']);
|
||||
|
||||
const orders = await orderService.getOrders(filter, options);
|
||||
res.status(httpStatus.OK).send(orders);
|
||||
});
|
||||
|
||||
export const getMyOrders = catchAsync(async (req: Request, res: Response) => {
|
||||
console.log(req.params);
|
||||
|
||||
const filter = pick(req.query, ['status', 'id']);
|
||||
const options = pick(req.query, ['sortBy', 'limit', 'page']);
|
||||
|
||||
filter.username = req.params.username;
|
||||
|
||||
const orders = await orderService.getOrders(filter, options);
|
||||
res.status(httpStatus.OK).send(orders);
|
||||
});
|
||||
|
||||
export const setStatus = catchAsync(async (req: Request, res: Response) => {
|
||||
const { status, id } = req.body;
|
||||
|
||||
await orderService.setStatus(id, status);
|
||||
|
||||
res.status(httpStatus.OK).send();
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
import httpStatus from 'http-status';
|
||||
import { participantService } from '../services';
|
||||
import type { RJoinCooperative } from '../types';
|
||||
import catchAsync from '../utils/catchAsync';
|
||||
|
||||
export const joinCooperative = catchAsync(async (req: RJoinCooperative, res) => {
|
||||
await participantService.joinCooperative(req.body);
|
||||
|
||||
res.status(httpStatus.OK).send();
|
||||
});
|
||||
@@ -1,112 +0,0 @@
|
||||
import http from 'http-status';
|
||||
import catchAsync from '../utils/catchAsync';
|
||||
import { paymentService } from '../services';
|
||||
import {
|
||||
ICreateDeposit,
|
||||
ICreateInitialPayment,
|
||||
RDeletePaymentMethod,
|
||||
RGetListPaymentMethods,
|
||||
RSavePaymentMethod,
|
||||
} from '../types';
|
||||
import { Request, Response } from 'express';
|
||||
import * as ip from 'ip';
|
||||
import { IGetResponse } from '../types/common';
|
||||
import ApiError from '../utils/ApiError';
|
||||
import httpStatus from 'http-status';
|
||||
import { Cooperative } from 'cooptypes';
|
||||
import { getUserByUsername } from '../services/user.service';
|
||||
import { User } from '../models';
|
||||
|
||||
// Список разрешенных IP-адресов
|
||||
// const allowedIPs = [
|
||||
// '185.71.76.0/27',
|
||||
// '185.71.77.0/27',
|
||||
// '77.75.153.0/25',
|
||||
// '77.75.156.11',
|
||||
// '77.75.156.35',
|
||||
// '77.75.154.128/25',
|
||||
// '2a02:5180::/32'
|
||||
// ];
|
||||
|
||||
// if (process.env.NODE_ENV === 'development')
|
||||
// allowedIPs.push('127.0.0.1')
|
||||
|
||||
export const catchIPN = catchAsync(async (req: Request, res: Response) => {
|
||||
// const ipAddr = ((req.headers['x-real-ip'] as string) || req.ip || '').replace(/^::ffff:/, '');
|
||||
// console.log("ip: ", ipAddr);
|
||||
|
||||
// const isAllowed = allowedIPs.some(allowedIP => {
|
||||
// if (allowedIP.includes('/')) { // Если это диапазон
|
||||
// return ip.cidrSubnet(allowedIP).contains(ipAddr);
|
||||
// }
|
||||
// return allowedIP === ipAddr; // Если это конкретный IP
|
||||
// });
|
||||
|
||||
// if (!isAllowed) {
|
||||
// console.log("попытка доступа с запрещенного IP: ", ipAddr)
|
||||
// return res.status(http.FORBIDDEN).send('Доступ запрещен');
|
||||
// }
|
||||
|
||||
// console.log("on catch ipn", req.body);
|
||||
|
||||
res.status(http.OK).send();
|
||||
paymentService.catchIPN(req.body);
|
||||
});
|
||||
|
||||
export const createDeposit = catchAsync(async (req: any, res: Response) => {
|
||||
const username = req.user.username;
|
||||
|
||||
const result = await paymentService.createDeposit(username, req.body as ICreateDeposit);
|
||||
res.status(http.CREATED).send(result);
|
||||
});
|
||||
|
||||
export const createInitialPayment = catchAsync(async (req: any, res: Response) => {
|
||||
const username = req.user.username;
|
||||
const result = await paymentService.createInitialOrder(username, req.body as ICreateInitialPayment);
|
||||
res.status(http.CREATED).send(result);
|
||||
});
|
||||
|
||||
export const listPaymentMethods = catchAsync(async (req: RGetListPaymentMethods, res) => {
|
||||
const filter = req.params?.username ? { username: req.params.username } : {};
|
||||
|
||||
const methods: IGetResponse<any> = await paymentService.listPaymentMethods({ ...filter });
|
||||
|
||||
res.status(httpStatus.OK).send(methods);
|
||||
});
|
||||
|
||||
export const addPaymentMethod = catchAsync(async (req: RSavePaymentMethod, res) => {
|
||||
if (req.params?.username != req.body.username)
|
||||
throw new ApiError(httpStatus.BAD_REQUEST, 'username в params и body должны совпадать');
|
||||
|
||||
const user = await getUserByUsername(req.body.username);
|
||||
|
||||
const method = req.body as any;
|
||||
|
||||
if (method.method_type === 'sbp' && !method.data.phone)
|
||||
throw new ApiError(httpStatus.BAD_REQUEST, 'Не указан телефон для метода СБП');
|
||||
|
||||
if (method.method_type === 'bank_transfer' && !method.data.account_number)
|
||||
throw new ApiError(httpStatus.BAD_REQUEST, 'Не верно указаны реквизиты для банковского платежа');
|
||||
|
||||
const paymentData: Cooperative.Payments.IPaymentData = {
|
||||
username: req.body.username,
|
||||
method_id: req.body.method_id,
|
||||
user_type: user.type,
|
||||
method_type: req.body.method_type,
|
||||
is_default: false,
|
||||
data: req.body.data,
|
||||
};
|
||||
|
||||
await paymentService.savePaymentMethod(paymentData);
|
||||
|
||||
res.status(httpStatus.OK).send();
|
||||
});
|
||||
|
||||
export const deletePaymentMethod = catchAsync(async (req: RDeletePaymentMethod, res) => {
|
||||
await paymentService.deletePaymentMethod({
|
||||
username: req.params?.username,
|
||||
method_id: req.body.method_id,
|
||||
});
|
||||
|
||||
res.status(httpStatus.OK).send();
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import { Request, Response } from 'express';
|
||||
import { pluginService } from '../services';
|
||||
import httpStatus from 'http-status';
|
||||
import type { RGetPluginConfig, RGetPluginList, RGetPluginSchema, RSetPlugin } from '../types';
|
||||
import ApiError from '../utils/ApiError';
|
||||
import catchAsync from '../utils/catchAsync';
|
||||
import { restartWorker, terminateWorker } from '../plugins/pluginFactory';
|
||||
import pick from '../utils/pick';
|
||||
|
||||
export const getPluginList = catchAsync(async (req: RGetPluginList, res: Response) => {
|
||||
const filter = pick(req.query, ['name']);
|
||||
const options = pick(req.query, ['sortBy', 'limit', 'page']);
|
||||
|
||||
const plugins = await pluginService.queryPlugins(filter, options);
|
||||
|
||||
res.send(plugins);
|
||||
});
|
||||
|
||||
// Контроллер для обновления параметров плагинов
|
||||
export const setPluginConfig = catchAsync(async (req: RSetPlugin, res: Response) => {
|
||||
const { name, config, enabled } = req.body;
|
||||
try {
|
||||
const updatedConfig = await pluginService.updatePluginConfig(name, enabled, config);
|
||||
|
||||
if (enabled == false) await terminateWorker(name);
|
||||
else await restartWorker(name);
|
||||
|
||||
res.status(httpStatus.OK).json({
|
||||
message: `Конфигурация плагина ${name} успешно обновлена`,
|
||||
config: updatedConfig,
|
||||
});
|
||||
} catch (e: any) {
|
||||
throw new ApiError(httpStatus.BAD_REQUEST, e.message);
|
||||
}
|
||||
});
|
||||
|
||||
// Контроллер для обновления параметров плагинов
|
||||
export const getPluginSchema = catchAsync(async (req: RGetPluginSchema, res: Response) => {
|
||||
const { name } = req.query;
|
||||
try {
|
||||
const schema = pluginService.getPluginSchema(name);
|
||||
res.status(httpStatus.OK).json(schema);
|
||||
} catch (e: any) {
|
||||
throw new ApiError(httpStatus.BAD_REQUEST, e.message);
|
||||
}
|
||||
});
|
||||
|
||||
// Контроллер для обновления параметров плагинов
|
||||
export const getPluginConfig = catchAsync(async (req: RGetPluginConfig, res: Response) => {
|
||||
const { name } = req.query;
|
||||
console.log('plugin', name);
|
||||
const config = await pluginService.getPluginConfig(name);
|
||||
|
||||
res.status(httpStatus.OK).json(config);
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { settingService } from '../services';
|
||||
import catchAsync from '../utils/catchAsync';
|
||||
|
||||
import httpStatus from 'http-status';
|
||||
|
||||
export const updateSettings = catchAsync(async (req, res) => {
|
||||
const { settings } = req.body;
|
||||
|
||||
await settingService.updateSettings(settings);
|
||||
|
||||
res.status(httpStatus.OK).send();
|
||||
});
|
||||
|
||||
export const getSettings = catchAsync(async (req, res) => {
|
||||
const settings = await settingService.getSettings();
|
||||
|
||||
res.status(httpStatus.OK).send(settings);
|
||||
});
|
||||
@@ -0,0 +1,57 @@
|
||||
import httpStatus from 'http-status';
|
||||
import { getMonoStatus } from '../services/system.service';
|
||||
import { getBlockchainInfo } from '../services/blockchain.service';
|
||||
import { IHealthResponse, IInstall, RInstall } from '../types';
|
||||
import { Request, Response } from 'express';
|
||||
import catchAsync from '../utils/catchAsync';
|
||||
import { systemService } from '../services';
|
||||
import type { IInit, ISetVars, RInit, RSetVars, RSetWif } from '../types/auto-generated/system.validation';
|
||||
import logger from '../config/logger';
|
||||
|
||||
export const init = catchAsync(async (req: RInit, res: Response) => {
|
||||
const { body } = req;
|
||||
await systemService.init(body as IInit);
|
||||
|
||||
res.status(httpStatus.OK).send();
|
||||
});
|
||||
|
||||
export const install = catchAsync(async (req: RInstall, res: Response) => {
|
||||
const { body } = req;
|
||||
await systemService.install(body as IInstall);
|
||||
|
||||
logger.info('System installed');
|
||||
|
||||
res.status(httpStatus.OK).send();
|
||||
});
|
||||
|
||||
export const setWif = catchAsync(async (req: RSetWif, res: Response) => {
|
||||
await systemService.setWif(req.body);
|
||||
res.status(httpStatus.OK).send();
|
||||
});
|
||||
|
||||
export const getHealth = catchAsync(async (req: Request, res: Response) => {
|
||||
const status = await getMonoStatus();
|
||||
const blockchain = await getBlockchainInfo();
|
||||
|
||||
const result: IHealthResponse = {
|
||||
status,
|
||||
blockchain,
|
||||
};
|
||||
|
||||
res.status(httpStatus.OK).send(result);
|
||||
});
|
||||
|
||||
export const setVars = catchAsync(async (req: RSetVars, res: Response) => {
|
||||
await systemService.setVars(req.body as ISetVars);
|
||||
res.status(httpStatus.OK).send();
|
||||
});
|
||||
|
||||
export const getVarsSchema = catchAsync(async (req: RSetVars, res: Response) => {
|
||||
const schema = await systemService.getVarsSchema();
|
||||
res.status(httpStatus.OK).send(schema);
|
||||
});
|
||||
|
||||
export const getVars = catchAsync(async (req: RSetVars, res: Response) => {
|
||||
const vars = await systemService.getVars();
|
||||
res.status(httpStatus.OK).send(vars);
|
||||
});
|
||||
@@ -2,15 +2,29 @@ import http from 'http-status';
|
||||
import ApiError from '../utils/ApiError';
|
||||
import catchAsync from '../utils/catchAsync';
|
||||
import { userService, tokenService, emailService, blockchainService } from '../services';
|
||||
import { IAddUser, ICreateUser, RCreateUser, RJoinCooperative } from '../types';
|
||||
import { IAddUser, ICreateUser, RCreateUser } from '../types';
|
||||
import httpStatus from 'http-status';
|
||||
import pick from '../utils/pick';
|
||||
import { IGetResponse } from '../types/common';
|
||||
import { IUser } from '../models/user.model';
|
||||
// import { IGetResponse } from '../types/common';
|
||||
import { IUser, userStatus } from '../types';
|
||||
import { Request, Response } from 'express';
|
||||
import { generateUsername } from '../../tests/utils/generateUsername';
|
||||
import config from '../config/config';
|
||||
import logger from '../config/logger';
|
||||
// import { Body, Controller, Get, Path, Post, Query, Route, SuccessResponse } from 'tsoa';
|
||||
|
||||
// @Route('users')
|
||||
// export default class UsersController extends Controller {
|
||||
// @SuccessResponse(201, 'Created') // Указываем статус 201 и описание
|
||||
// @Post()
|
||||
// public async createUser(@Body() req: RCreateUser): Promise<{ user: IUser; tokens: any }> {
|
||||
// const user = await userService.createUser(req.body);
|
||||
// const tokens = await tokenService.generateAuthTokens(user);
|
||||
|
||||
// this.setStatus(201); // Устанавливаем статус 201 Created
|
||||
// return { user, tokens }; // Возвращаем объект в ответ
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Порядок регистрации:
|
||||
@@ -23,10 +37,11 @@ import logger from '../config/logger';
|
||||
* 7. (joinCooperative) Пользователь подписывает заявление на вступление и вызывает метод joinCooperative, прикладывая подписанное заявление.
|
||||
* 8. Система сохраняет подписанное заявление
|
||||
* 9. (createInitialPayment) Пользователь получает ордер на оплату.
|
||||
* 9. Пользователь оплачивает ордер.
|
||||
* 10. Система принимает оплату и регистрирует аккаунт в блокчейне.
|
||||
* 11. (trx confirmpay) Пользователь подписывает велком-письмо с подтверждением собственноручности оплаты (транзакция в блокчейне для активации)
|
||||
* 12. Регистрация продолжается ожиданием решения совета
|
||||
*/
|
||||
|
||||
export const createUser = catchAsync(async (req: RCreateUser, res) => {
|
||||
const user = await userService.createUser(req.body);
|
||||
const tokens = await tokenService.generateAuthTokens(user);
|
||||
@@ -36,7 +51,7 @@ export const createUser = catchAsync(async (req: RCreateUser, res) => {
|
||||
|
||||
export const addUser = catchAsync(async (req: Request, res: Response) => {
|
||||
const body: IAddUser = req.body;
|
||||
|
||||
console.log('body: ', body);
|
||||
const newUser: ICreateUser = {
|
||||
...body,
|
||||
public_key: '',
|
||||
@@ -45,12 +60,17 @@ export const addUser = catchAsync(async (req: Request, res: Response) => {
|
||||
};
|
||||
|
||||
const user = await userService.createUser(newUser);
|
||||
user.status = userStatus['4_Registered'];
|
||||
user.is_registered = true;
|
||||
user.has_account = true;
|
||||
|
||||
await user.save();
|
||||
|
||||
try {
|
||||
await blockchainService.addUser({
|
||||
...body,
|
||||
...newUser,
|
||||
registrator: config.service_username,
|
||||
registrator: config.coopname,
|
||||
referer: body.referer ? body.referer : '',
|
||||
coopname: config.coopname,
|
||||
meta: '',
|
||||
@@ -58,55 +78,27 @@ export const addUser = catchAsync(async (req: Request, res: Response) => {
|
||||
|
||||
const token = await tokenService.generateInviteToken(user.email);
|
||||
await emailService.sendInviteEmail(req.body.email, token);
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
logger.warn('error on add user: ', e);
|
||||
await userService.deleteUserByUsername(newUser.username);
|
||||
throw new ApiError(httpStatus.BAD_GATEWAY, e.message);
|
||||
}
|
||||
|
||||
res.status(httpStatus.CREATED).send({ user });
|
||||
});
|
||||
|
||||
export const joinCooperative = catchAsync(async (req: RJoinCooperative, res) => {
|
||||
await userService.joinCooperative(req.body);
|
||||
|
||||
res.status(httpStatus.OK).send();
|
||||
});
|
||||
|
||||
export const getUsers = catchAsync(async (req, res) => {
|
||||
const filter = pick(req.query, ['username', 'role']);
|
||||
const options = pick(req.query, ['sortBy', 'limit', 'page']);
|
||||
|
||||
const users = await userService.queryUsers(filter, options);
|
||||
const result = {} as IGetResponse<IUser>;
|
||||
|
||||
const data = [] as any;
|
||||
for await (const user of users.results) {
|
||||
const json = user.toJSON();
|
||||
if (user.type != 'service') {
|
||||
json.private_data = (await user.getPrivateData()) || {};
|
||||
data.push(json);
|
||||
}
|
||||
}
|
||||
|
||||
result.results = data;
|
||||
result.limit = users.limit;
|
||||
result.page = users.page;
|
||||
result.totalPages = users.totalPages;
|
||||
result.totalResults = users.totalResults;
|
||||
|
||||
res.send(result);
|
||||
res.send(users);
|
||||
});
|
||||
|
||||
export const getUser = catchAsync(async (req, res) => {
|
||||
const user = await userService.getUserByUsername(req.params.username);
|
||||
if (!user) {
|
||||
throw new ApiError(http.NOT_FOUND, 'Пользователь не найден');
|
||||
}
|
||||
const json = user.toJSON();
|
||||
|
||||
json.private_data = await user.getPrivateData();
|
||||
|
||||
res.send(json);
|
||||
res.send(user);
|
||||
});
|
||||
|
||||
export const updateUser = catchAsync(async (req, res) => {
|
||||
|
||||
@@ -2,6 +2,8 @@ import { io, Socket } from 'socket.io-client';
|
||||
import { IAction } from '../types/common';
|
||||
import { SovietContract } from 'cooptypes';
|
||||
import { wsService } from '../services';
|
||||
import logger from '../config/logger';
|
||||
import config from '../config/config';
|
||||
|
||||
let clientSocket: Socket | undefined;
|
||||
|
||||
@@ -10,7 +12,7 @@ export const initSocketConnection = (serverUrl: string): void => {
|
||||
clientSocket = io(serverUrl);
|
||||
|
||||
clientSocket.on('connect', () => {
|
||||
console.log('Успешное подключение к серверу оповещений.');
|
||||
logger.info('Success connection to notification server', { source: 'initSocketConnection' });
|
||||
});
|
||||
|
||||
clientSocket.on('event', (event: IAction) => {
|
||||
@@ -18,7 +20,7 @@ export const initSocketConnection = (serverUrl: string): void => {
|
||||
});
|
||||
|
||||
clientSocket.on('connect_error', (error: Error) => {
|
||||
console.error('Ошибка подключения к серверу оповещений:');
|
||||
logger.error('Fail connect to notification server', { source: 'initSocketConnection' });
|
||||
});
|
||||
};
|
||||
|
||||
@@ -26,13 +28,19 @@ export const initSocketConnection = (serverUrl: string): void => {
|
||||
export const closeSocketConnection = (): void => {
|
||||
if (clientSocket) {
|
||||
clientSocket.disconnect();
|
||||
console.log('Client disconnected from server');
|
||||
logger.info('Client disconnected from server', { source: 'closeSocketConnection' });
|
||||
clientSocket = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
async function processEvent(event: IAction) {
|
||||
if (event.receiver === SovietContract.contractName.production && event.name === 'updateboard') {
|
||||
wsService.updateBoard(event.data);
|
||||
if (event.receiver === config.coopname) {
|
||||
if (event.name === 'updateboard') {
|
||||
wsService.updateBoard(event.data);
|
||||
}
|
||||
|
||||
if (event.name === 'createboard') {
|
||||
wsService.updateBoard(event.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,73 +14,6 @@
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/auth/register": {
|
||||
"post": {
|
||||
"summary": "Register as user",
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"email",
|
||||
"password"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "must be unique"
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"format": "password",
|
||||
"minLength": 8,
|
||||
"description": "At least one number and one letter"
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"name": "fake name",
|
||||
"email": "fake@example.com",
|
||||
"password": "password1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"user": {
|
||||
"$ref": "#/components/schemas/User"
|
||||
},
|
||||
"tokens": {
|
||||
"$ref": "#/components/schemas/AuthTokens"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"$ref": "#/components/responses/DuplicateEmail"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/login": {
|
||||
"post": {
|
||||
"summary": "Login",
|
||||
@@ -844,11 +777,11 @@
|
||||
"ICreatedPayment": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"order_id",
|
||||
"order_num",
|
||||
"confirmation_token"
|
||||
],
|
||||
"properties": {
|
||||
"order_id": {
|
||||
"order_num": {
|
||||
"type": "number"
|
||||
},
|
||||
"confirmation_token": {
|
||||
@@ -1290,7 +1223,7 @@
|
||||
"tags": [
|
||||
{
|
||||
"name": "Auth",
|
||||
"description": "Authentication"
|
||||
"description": "Управление аудентификацией"
|
||||
},
|
||||
{
|
||||
"name": "Orders",
|
||||
|
||||
@@ -3,7 +3,7 @@ import config from '../config/config';
|
||||
const swaggerDef = {
|
||||
openapi: '3.0.0',
|
||||
info: {
|
||||
title: "API Цифрового Кооператива",
|
||||
title: 'API Цифрового Кооператива',
|
||||
// description: `Модуль предоставляет:
|
||||
|
||||
// - API для хранения персональных данных пользователей
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
export * from './types';
|
||||
|
||||
import mongoose from 'mongoose';
|
||||
import app from './app';
|
||||
import config from './config/config';
|
||||
import logger from './config/logger';
|
||||
import { connectGenerator } from './services/document.service';
|
||||
import { initPolling } from './services/polling.service';
|
||||
import { redisSubscriber } from './services/redis.service';
|
||||
|
||||
let server: any;
|
||||
|
||||
mongoose.connect(config.mongoose.url).then(async () => {
|
||||
logger.info('Connected to MongoDB with payment processor');
|
||||
|
||||
// подключаемся к хранилищу приватных данных
|
||||
await connectGenerator();
|
||||
|
||||
redisSubscriber.subscribe(`${config.coopname}:orderStatusUpdate`, (err, count) => {
|
||||
if (err) {
|
||||
logger.error('Failed to subscribe: ', err);
|
||||
} else {
|
||||
logger.info(`Subscribed successfully! This client is currently subscribed to ${count} channels.`);
|
||||
}
|
||||
});
|
||||
|
||||
redisSubscriber.on('message', (channel, message) => {
|
||||
if (channel === `${config.coopname}:orderStatusUpdate` && message) {
|
||||
const { orderId, status } = JSON.parse(message);
|
||||
// Дальнейшая обработка
|
||||
}
|
||||
});
|
||||
|
||||
initPolling();
|
||||
});
|
||||
|
||||
const exitHandler = () => {
|
||||
if (server) {
|
||||
server.close(() => {
|
||||
logger.info('Server closed');
|
||||
process.exit(1);
|
||||
});
|
||||
} else {
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
const unexpectedErrorHandler = (error: any) => {
|
||||
logger.error(error);
|
||||
exitHandler();
|
||||
};
|
||||
|
||||
process.on('uncaughtException', unexpectedErrorHandler);
|
||||
process.on('unhandledRejection', unexpectedErrorHandler);
|
||||
|
||||
process.on('SIGTERM', () => {
|
||||
logger.info('SIGTERM received');
|
||||
if (server) {
|
||||
server.close();
|
||||
}
|
||||
});
|
||||
@@ -4,9 +4,11 @@ import mongoose from 'mongoose';
|
||||
import app from './app';
|
||||
import config from './config/config';
|
||||
import logger from './config/logger';
|
||||
import { connectGenerator } from './services/document.service';
|
||||
import { connectGenerator, diconnectGenerator } from './services/document.service';
|
||||
import { initSocketConnection } from './controllers/ws.controller';
|
||||
import { monoService } from './services';
|
||||
import { pluginFactory } from './plugins/pluginFactory';
|
||||
import { paymentService } from './services';
|
||||
import { initializeDefaultPlugins } from './services/plugin.service';
|
||||
|
||||
const SERVER_URL: string = process.env.SOCKET_SERVER || 'http://localhost:2222';
|
||||
|
||||
@@ -15,20 +17,27 @@ let server: any;
|
||||
mongoose.connect(config.mongoose.url).then(async () => {
|
||||
logger.info('Connected to MongoDB');
|
||||
|
||||
await monoService.init();
|
||||
|
||||
// подключаемся к хранилищу приватных данных
|
||||
await connectGenerator();
|
||||
|
||||
// подключаемся к ws-серверу
|
||||
await initSocketConnection(SERVER_URL);
|
||||
|
||||
// Запуск фабрики платежей
|
||||
await paymentService.init();
|
||||
|
||||
// Инициализация дефолтных плагинов
|
||||
await initializeDefaultPlugins();
|
||||
|
||||
// // Запуск плагинов
|
||||
await pluginFactory();
|
||||
|
||||
server = app.listen(config.port, () => {
|
||||
logger.info(`Listening to port ${config.port}`);
|
||||
});
|
||||
});
|
||||
|
||||
const exitHandler = () => {
|
||||
const exitHandler = async () => {
|
||||
if (server) {
|
||||
server.close(() => {
|
||||
logger.info('Server closed');
|
||||
@@ -39,16 +48,20 @@ const exitHandler = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const unexpectedErrorHandler = (error: any) => {
|
||||
logger.error(error);
|
||||
exitHandler();
|
||||
const unexpectedErrorHandler = async (error: any) => {
|
||||
console.log(error);
|
||||
await diconnectGenerator();
|
||||
await mongoose.disconnect();
|
||||
logger.error(error, { source: 'unexpectedErrorHandler' });
|
||||
await exitHandler();
|
||||
};
|
||||
|
||||
process.on('uncaughtException', unexpectedErrorHandler);
|
||||
process.on('unhandledRejection', unexpectedErrorHandler);
|
||||
|
||||
process.on('SIGTERM', () => {
|
||||
process.on('SIGTERM', async () => {
|
||||
logger.info('SIGTERM received');
|
||||
await mongoose.disconnect();
|
||||
if (server) {
|
||||
server.close();
|
||||
}
|
||||
|
||||
@@ -6,19 +6,32 @@ import { roleRights } from '../config/roles';
|
||||
const { UNAUTHORIZED, FORBIDDEN } = httpStatus;
|
||||
|
||||
const verifyCallback = (req, resolve, reject, requiredRights) => async (err, user, info) => {
|
||||
const serverSecret = process.env.SERVER_SECRET;
|
||||
|
||||
// Check for server-secret header
|
||||
if (serverSecret && req.headers['server-secret'] === serverSecret) {
|
||||
return resolve();
|
||||
}
|
||||
|
||||
if (err || info || !user) {
|
||||
return reject(new ApiError(UNAUTHORIZED, 'Please authenticate'));
|
||||
}
|
||||
|
||||
req.user = user;
|
||||
|
||||
if (requiredRights.length) {
|
||||
const userRights = roleRights.get(user.role);
|
||||
const hasRequiredRights = requiredRights.every((requiredRight) => userRights?.includes(requiredRight));
|
||||
const userRights = roleRights.get(user.role) || [];
|
||||
|
||||
if (!hasRequiredRights && req.params.username !== user.username) {
|
||||
//
|
||||
return reject(new ApiError(FORBIDDEN, 'Недостаточно прав доступа'));
|
||||
}
|
||||
// Determine if user has the required rights
|
||||
const hasRequiredRights = requiredRights.every((requiredRight) => userRights.includes(requiredRight));
|
||||
|
||||
// Check if user is accessing their own resource
|
||||
const isOwnResource =
|
||||
(req.params.username && req.params.username === user.username) || //для аудентификации по username в params
|
||||
(req.body.username && req.body.username === user.username) || //для аудентификации по username в body
|
||||
(req.body.data && req.body.data.username && req.body.data.username === user.username); //для аудентификации при генерации документов
|
||||
|
||||
if (!isOwnResource && (!hasRequiredRights || !requiredRights.length)) {
|
||||
return reject(new ApiError(FORBIDDEN, 'Недостаточно прав доступа'));
|
||||
}
|
||||
|
||||
resolve();
|
||||
|
||||
@@ -40,9 +40,7 @@ export const errorHandler = (err, req, res, next?) => {
|
||||
...(config.env === 'development' && { stack: err.stack }),
|
||||
};
|
||||
|
||||
if (config.env === 'development') {
|
||||
logger.error(err);
|
||||
}
|
||||
logger.error(err);
|
||||
|
||||
res.status(statusCode).send(response);
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@ import ApiError from '../utils/ApiError';
|
||||
|
||||
const validate = (schema) => (req, res, next) => {
|
||||
// Фильтрация ключей, чтобы убедиться, что они существуют и не пусты
|
||||
const validKeys = ['params', 'query', 'body'].filter(key => req[key] && Object.keys(req[key]).length > 0);
|
||||
const validKeys = ['params', 'query', 'body'].filter((key) => req[key] && Object.keys(req[key]).length > 0);
|
||||
const object = pick(req, validKeys);
|
||||
|
||||
const { value, error } = joi
|
||||
@@ -21,5 +21,4 @@ const validate = (schema) => (req, res, next) => {
|
||||
return next();
|
||||
};
|
||||
|
||||
|
||||
export default validate;
|
||||
|
||||
@@ -2,3 +2,4 @@ export { default as Token } from './token.model';
|
||||
export { default as User } from './user.model';
|
||||
export { default as Order } from './order.model';
|
||||
export { default as Mono } from './mono.model';
|
||||
export * from './settings.model';
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import mongoose, { Schema, Document, model } from 'mongoose';
|
||||
import { toJSON, paginate } from './plugins/index';
|
||||
|
||||
export interface IIpn {
|
||||
provider: string;
|
||||
data: object;
|
||||
}
|
||||
|
||||
const ipnSchema = new Schema<IIpn>(
|
||||
{
|
||||
provider: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
|
||||
// add plugin that converts mongoose to json
|
||||
ipnSchema.plugin(toJSON);
|
||||
ipnSchema.plugin(paginate);
|
||||
|
||||
/**
|
||||
* @typedef Ipn
|
||||
*/
|
||||
const IPN = model<IIpn>('Ipn', ipnSchema);
|
||||
|
||||
export default IPN;
|
||||
@@ -1,62 +1,74 @@
|
||||
import mongoose, { Schema, Document, model } from 'mongoose';
|
||||
import mongoose, { Schema, Document, model, type Model } from 'mongoose';
|
||||
import { toJSON, paginate } from './plugins/index';
|
||||
import AutoIncrementFactory from 'mongoose-sequence';
|
||||
import { generateOrderSecret } from '../services/order.service';
|
||||
import { type IOrder, orderStatus } from '../types/order.types';
|
||||
|
||||
interface IOrder extends Document {
|
||||
creator: string;
|
||||
type: string;
|
||||
data: {
|
||||
username: string;
|
||||
provider: string;
|
||||
quantity: string;
|
||||
};
|
||||
order_id?: number;
|
||||
payed?: boolean;
|
||||
delivered?: boolean;
|
||||
error?: object;
|
||||
expired_at?: Date;
|
||||
const AutoIncrement = AutoIncrementFactory(mongoose);
|
||||
|
||||
interface IOrderModel extends Model<IOrder> {
|
||||
isEmailTaken(email: string, excludeUsername?: mongoose.Types.ObjectId): Promise<boolean>;
|
||||
paginate(filter, options): any;
|
||||
}
|
||||
|
||||
const orderSchema = new Schema<IOrder>(
|
||||
const orderSchema = new Schema<IOrder, IOrderModel>(
|
||||
{
|
||||
order_num: {
|
||||
type: Number,
|
||||
required: false,
|
||||
unique: true,
|
||||
},
|
||||
creator: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
secret: {
|
||||
type: String,
|
||||
required: true,
|
||||
private: true,
|
||||
default: () => generateOrderSecret(16), // Генерация секрета по умолчанию
|
||||
},
|
||||
status: {
|
||||
type: String,
|
||||
enum: Object.values(orderStatus),
|
||||
default: orderStatus.pending,
|
||||
},
|
||||
message: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
enum: ['registration', 'deposit'],
|
||||
required: true,
|
||||
},
|
||||
provider: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
data: {
|
||||
provider: {
|
||||
type: String,
|
||||
required: true,
|
||||
username: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
quantity: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
symbol: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
details: {
|
||||
type: {
|
||||
data: { type: Schema.Types.Mixed, required: true },
|
||||
amount_plus_fee: { type: String, required: true },
|
||||
amount_without_fee: { type: String, required: true },
|
||||
fee_amount: { type: String, required: true },
|
||||
fee_percent: { type: Number, required: true },
|
||||
fact_fee_percent: { type: Number, required: true },
|
||||
tolerance_percent: { type: Number, required: true },
|
||||
},
|
||||
username: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
quantity: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
order_id: {
|
||||
type: Number,
|
||||
required: false,
|
||||
},
|
||||
payed: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
delivered: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
error: {
|
||||
type: Object,
|
||||
required: false,
|
||||
required: false, // Поле может быть не обязательным
|
||||
},
|
||||
expired_at: {
|
||||
type: Date,
|
||||
@@ -66,19 +78,40 @@ const orderSchema = new Schema<IOrder>(
|
||||
return now;
|
||||
},
|
||||
},
|
||||
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true }, // Связь с пользователем
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
|
||||
// Хук после find для автоматического добавления private_data
|
||||
orderSchema.post('find', async function (docs) {
|
||||
for (const doc of docs) {
|
||||
// Наполняем пользователя с помощью populate
|
||||
await doc.populate('user');
|
||||
// Если пользователь найден, вызываем асинхронный метод getPrivateData
|
||||
if (doc.user) {
|
||||
doc.user.private_data = await doc.user.getPrivateData();
|
||||
}
|
||||
|
||||
// Проверяем поле expired_at и обновляем статус
|
||||
if (doc.status != orderStatus.expired && doc.expired_at && new Date() > doc.expired_at) {
|
||||
doc.status = orderStatus.expired;
|
||||
await doc.save(); // Сохраняем изменения в документе
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// add plugin that converts mongoose to json
|
||||
orderSchema.plugin(toJSON);
|
||||
orderSchema.plugin(paginate);
|
||||
// Добавляем автоинкремент для поля order_num
|
||||
orderSchema.plugin(AutoIncrement, { inc_field: 'order_num' });
|
||||
|
||||
/**
|
||||
* @typedef Order
|
||||
*/
|
||||
const Order = model<IOrder>('Order', orderSchema);
|
||||
const Order = model<IOrder, IOrderModel>('Order', orderSchema);
|
||||
|
||||
export default Order;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// models/PaymentState.ts
|
||||
|
||||
import { Schema, model } from 'mongoose';
|
||||
|
||||
interface IPaymentState {
|
||||
accountNumber: string;
|
||||
statementDate: string;
|
||||
lastProcessedPage: number;
|
||||
}
|
||||
|
||||
const PaymentStateSchema = new Schema<IPaymentState>({
|
||||
accountNumber: { type: String, required: true },
|
||||
statementDate: { type: String, required: true },
|
||||
lastProcessedPage: { type: Number, required: true },
|
||||
});
|
||||
|
||||
export const PaymentState = model<IPaymentState>('PaymentState', PaymentStateSchema);
|
||||
@@ -0,0 +1,25 @@
|
||||
import { Schema, model, type Model } from 'mongoose';
|
||||
import type { IPluginSchema } from '../types/plugin.types';
|
||||
import { paginate, toJSON } from './plugins';
|
||||
|
||||
interface IPaginate extends Model<IPluginSchema<any>> {
|
||||
paginate(filter, options): any;
|
||||
}
|
||||
|
||||
export const pluginSchema = new Schema<IPluginSchema<any>, IPaginate>(
|
||||
{
|
||||
name: { type: String, required: true },
|
||||
enabled: { type: Boolean, default: true },
|
||||
config: { type: Schema.Types.Mixed }, // Своя конфигурация для каждого плагина
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
|
||||
// add plugin that converts mongoose to json
|
||||
pluginSchema.plugin(toJSON);
|
||||
pluginSchema.plugin(paginate);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export const PluginConfig = model<IPluginSchema<any>, IPaginate>('Plugins', pluginSchema);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user