sequelize-game-bank 3.0.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  > # sequelize-game-bank
2
2
 
3
- <img src="./src/logo/icon.png" alt="sequelize-game-bank logo" width="160" height="160" style="border-radius: 12%; margin-bottom: 20px;" />
3
+ <img src="https://github.com/RPM-programmer/sequelize-game-bank/blob/main/src/logo/icon.png?raw=true" alt="sequelize-game-bank logo" width="160" height="160" style="border-radius: 12%; margin-bottom: 20px;" />
4
4
 
5
5
  ## npm модуль для создания полноценного банка на express, sequelize (sqlite).
6
6
 
@@ -15,50 +15,78 @@
15
15
 
16
16
  ## 🚀 Установка
17
17
 
18
- Установите пакет через ваш менеджер пакетов:
18
+ Установите пакет через менеджер пакетов:
19
19
 
20
20
  ```bash
21
21
  npm install sequelize-game-bank
22
22
  # или
23
23
  yarn add sequelize-game-bank
24
24
  ```
25
- ## Мажорный переход на v3.0.0 (Breaking Changes)
26
- ### В v3.0.0 изменили инициализацию! Теперь не:
27
- ```javascript
28
- const BANK = require('sequelize-game-bank');
29
-
30
- const app = (async function initBank(){
31
- try {
32
- return await BANK();
33
- } catch {
34
- console.log("Ошибка при инициализации банка!");
35
- }
36
- })();
37
- //app.listen(3000);
25
+ ## Установка и настройка (Инициализация)
26
+
27
+ Модуль `sequelize-game-bank` требует асинхронной инициализации базы данных и настройки роутов.
28
+
29
+ ### 1. Настройка окружения (.env)
30
+ После первого запуска откройте `.env` и настройте эти поля:
31
+
32
+ ```env
33
+ SEQUELIZE_GAME_BANK_INITIALIZED = true
34
+ JWT_SECRET = 0000
35
+ ROOT_PASSWORD = bank-root
36
+ GMAIL =
37
+ GOOGLE_APP_PASSWORD =
38
38
  ```
39
- ### а:
39
+
40
+ ### 2. Подключение в проект
41
+
42
+ Так как модуль является асинхронным, его необходимо подключать **ДО** финальных обработчиков несуществующих маршрутов (404) и ошибок сервера (500). Поместите вызов модуля внутрь асинхронного блока:
43
+
40
44
  ```javascript
41
- const BANK = require('sequelize-game-bank');
42
- const express = require("express");
43
- let cleanApp = express();
44
- const app = (async function init()=>{
45
- return await BANK(cleanApp);
46
- });
47
-
48
- //app.listen(3000)
45
+ const express = require('express');
46
+ const sequelize_game_bank = require('sequelize-game-bank');
47
+
48
+ const app = express();
49
+
50
+
51
+ (async () => {
52
+ try {
53
+ await sequelize_game_bank(app);
54
+
55
+ app.use((req, res) => {
56
+ res.status(404).send("<h1>404 - Страница не найдена</h1>");
57
+ });
58
+
59
+ app.use((err, req, res, next) => {
60
+ res.status(500).send("<h1>500 - Внутренняя ошибка сервера</h1>");
61
+ });
62
+
63
+ } catch (error) {
64
+ }
65
+ })();
66
+
67
+ module.exports = { app };
49
68
  ```
69
+ ## 🌐 Маршрутизация и точки входа (v4.0.0)
50
70
 
51
- ## 💻 Быстрый старт
71
+ В версии 4.0.0 вся логика путей полностью изолирована внутри модуля и работает в автоматическом режиме. Разработчику или пользователю доступны всего **3 основные веб-страницы** для ручного перехода из браузера:
52
72
 
53
- Просто подключите модуль в ваше существующее Express-приложение:
73
+ * **`GET`** `/bank/home.html` — Главная приветственная страница банка.
74
+ * **`GET`** `/bank/login.html` — Страница авторизации пользователей.
75
+ * **`GET`** `/bank/register.html` — Страница регистрации новых аккаунтов.
54
76
 
55
- ```javascript
56
- const BANK = require('sequelize-game-bank');
57
- const express = require("express");
58
- let cleanApp = express();
59
- const app = (async function init()=>{
60
- return await BANK(cleanApp);
61
- });
62
-
63
- //app.listen(3000)
64
- ```
77
+ ---
78
+
79
+ ### ⚙️ Как это работает изнутри (Автоматика модуля)
80
+
81
+ Вам больше не нужно вручную настраивать эндпоинты в основном проекте `CITY`. После подключения модуля в `server.js` автоматически разворачиваются два изолированных роутера:
82
+
83
+ 1. **Интерфейс банка (Префикс `/bank`)**
84
+ Автоматически управляет отображением всех внутренних страниц личного кабинета (панели управления, счета, переводы, кредиты, админка) и раздачей статических файлов (CSS, JS, загруженные аватарки).
85
+
86
+ 2. **Серверное API (Префикс `/api/bank`)**
87
+ Полностью берет на себя фоновый обмен JSON-данными между вашим фронтендом и базой данных Sequelize. На этот префикс автоматически завязаны все типы сетевых операций:
88
+ * Получение данных (`GET` запросы профилей, счетов, баланса и истории логов).
89
+ * Изменение состояния (`POST` запросы авторизации, переводов, кредитов и настройки 2FA).
90
+ * Удаление сущностей (`DELETE` запросы на закрытие игровых счетов).
91
+
92
+ ## Лицензия [ISC](LICENSE)
@@ -0,0 +1,34 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const process = require('process');
4
+ const envPath = path.resolve(process.cwd(), '.env');
5
+ const logger = require("custom-color-logs").print;
6
+ const defaultEnvContent = `
7
+ # ==============================================================================
8
+ # sequelize-game-bank v4.0.0
9
+ # ==============================================================================
10
+ SEQUELIZE_GAME_BANK_INITIALIZED = true
11
+ JWT_SECRET = 0000
12
+ ROOT_PASSWORD = bank-root
13
+ GMAIL = example@gmail.com
14
+ GOOGLE_APP_PASSWORD = abcd efgh ijkl mnop
15
+ `;
16
+ function initializeEnvironment() {
17
+ try {
18
+ if (!fs.existsSync(envPath)) {
19
+ fs.writeFileSync(envPath, defaultEnvContent, 'utf8');
20
+ } else {
21
+ const currentEnv = fs.readFileSync(envPath, 'utf8');
22
+ if (currentEnv.includes('SEQUELIZE_GAME_BANK_INITIALIZED')) {
23
+ require("dotenv").config({ path: envPath });
24
+ return;
25
+ }
26
+ fs.appendFileSync(envPath, `\n\n${defaultEnvContent}`, 'utf8');
27
+ }
28
+ } catch (err) {
29
+ console.log(logger.ServerError('Не удалось проверить или обновить .env:', err.message));
30
+ }
31
+ require("dotenv").config({ path: envPath });
32
+ }
33
+ initializeEnvironment();
34
+ module.exports = { envPath };
@@ -0,0 +1,35 @@
1
+ const { Sequelize } = require('sequelize');
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+ const dbDir = path.resolve(__dirname, '..');
5
+ const dbPath = path.join(dbDir, 'citybank.db');
6
+ const logger = require("custom-color-logs").print;
7
+ if (!fs.existsSync(dbDir)) {
8
+ fs.mkdirSync(dbDir, { recursive: true });
9
+ }
10
+ try {
11
+ if (fs.existsSync(dbPath)) {
12
+ const stats = fs.statSync(dbPath);
13
+ if (stats.size === 0) {
14
+ console.log(logger.DatabaseWarn("База данных пуста или повреждена!"))
15
+ }
16
+ }
17
+ } catch (e) {
18
+ console.log(logger.DatabaseError("Файл бд не найден или повреждён."))
19
+ process.exit(1);
20
+ }
21
+ const sequelize = new Sequelize({
22
+ dialect: 'sqlite',
23
+ storage: dbPath,
24
+ logging: false,
25
+ define: {
26
+ timestamps: true
27
+ },
28
+ /*dialectOptions:{
29
+ mode: 2,
30
+ },*/
31
+ retry:{
32
+ max: 5,
33
+ }
34
+ });
35
+ module.exports = sequelize;
@@ -35,7 +35,7 @@ module.exports = async function transferManny(fromId, toId, amount, pinCode, tot
35
35
  await t.rollback();
36
36
  return { status: false, statusCode: -23, message: 'Неверный пароль счета отправителя' };
37
37
  }
38
- if (fromAcc.user !== 'root' && parseFloat(fromAcc.manny) < numericAmount) {
38
+ if (parseFloat(fromAcc.manny) < numericAmount) {
39
39
  await t.rollback();
40
40
  return { status: false, statusCode: -11, message: 'Недостаточно средств на счете' };
41
41
  }
package/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  const logger = require("custom-color-logs").print;
2
2
  console.log(logger.ServerBankInfo("Модуль банка запущен!"))
3
- require('dotenv').config();
4
3
  const path = require("path")
4
+ const setupEnv = require(path.join(__dirname, "config", "setup-env.js"));
5
5
  const express = require('express');
6
6
  const cookieParser = require('cookie-parser');
7
7
  const bcrypt = require('bcrypt');
8
- const sequelize = require(path.join(__dirname, 'database', 'config', 'init-db.js'));
8
+ const sequelize = require(path.join(__dirname, 'database', 'config', 'init-db.js'));
9
9
  const User = require(path.join(__dirname, 'database', 'models', 'User.js'));
10
10
  const { writeTemplatesIfNotExist } = require(path.join(__dirname, 'database', 'services', 'bot', 'write.js'));
11
11
  const registerRoutes = require(path.join(__dirname, 'server', 'server.js'));
@@ -35,25 +35,33 @@ async function Bank(app) {
35
35
  }
36
36
  });
37
37
  console.log(logger.ServerBankInfo(`Супер пользвотель создан`))
38
- const configuredApp = registerRoutes(app);
39
- app.use('/css', express.static(path.join(__dirname, 'public', 'css')));
40
- app.use('/js', express.static(path.join(__dirname, 'public', 'js')));
41
- app.use('/uploads', express.static(path.join(__dirname, 'public', 'uploads')));
38
+ const gp = registerRoutes();
39
+ const get = gp.GET;
40
+ const post = gp.POST;
41
+ post.use('/css', express.static(path.join(__dirname, 'public', 'css')));
42
+ post.use('/js', express.static(path.join(__dirname, 'public', 'js')));
43
+ post.use('/uploads', express.static(path.join(__dirname, 'public', 'uploads')));
42
44
  const { verifyPageSession } = require(path.join(__dirname, 'server', 'middleware', 'auth'));
43
45
  const pages = ['general.html', 'profile.html', 'accounts.html', 'transfer.html', 'history.html', 'credit.html', 'admin.html'];
44
46
  pages.forEach(page => {
45
- app.get(`/${page}`, verifyPageSession, (req, res) => {
47
+ get.get(`/${page}`, verifyPageSession, (req, res) => {
46
48
  res.sendFile(path.join(__dirname, 'public', page));
47
49
  });
48
50
  });
49
- app.get('/login.html', (req, res) => res.sendFile(path.join(__dirname, 'public', 'login.html')));
50
- app.get('/register.html', (req, res) => res.sendFile(path.join(__dirname, 'public', 'register.html')));
51
- app.get('/home.html', (req, res) => res.sendFile(path.join(__dirname, 'public', 'home.html')));
51
+ get.get('/login.html', (req, res) => res.sendFile(path.join(__dirname, 'public', 'login.html')));
52
+ get.get('/register.html', (req, res) => res.sendFile(path.join(__dirname, 'public', 'register.html')));
53
+ get.get('/home.html', (req, res) => res.sendFile(path.join(__dirname, 'public', 'home.html')));
52
54
  app.get('/favicon.ico', (req, res) => res.sendFile(path.join(__dirname, 'public', 'icon', 'icon.png')));
53
- app.get('/', (req, res) => res.redirect('/home.html'));
55
+ get.get('/', (req, res) => res.redirect('/home.html'));
56
+
57
+
58
+
59
+
60
+ app.use("/bank", get);
61
+ app.use("/api/bank", post)
54
62
 
55
63
  require(path.join(__dirname, 'database', 'services', 'bot', 'cron-schedule'));
56
- return configuredApp;
64
+ return app;
57
65
  } catch (err) {
58
66
  console.log(logger.ServerBankError("Критическая ошибка инициализации модулей", err));
59
67
  throw err;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sequelize-game-bank",
3
- "version": "3.0.1",
3
+ "version": "4.0.0",
4
4
  "description": "A Sequelize-based gaming economy and banking system featuring user profiles, credits, admin management, and detailed transaction history.",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",
@@ -3,25 +3,25 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <title>City-Bank | Мои Счета</title>
6
- <link rel="stylesheet" href="/css/style.css">
6
+ <link rel="stylesheet" href="/api/bank/css/style.css">
7
7
  <link rel="stylesheet" href="https://unpkg.com/tippy.js@6/animations/scale.css"/>
8
8
  </head>
9
9
  <body>
10
10
  <div class="main-container">
11
11
  <div class="sidebar">
12
12
  <div style="text-align: center; margin-bottom: 15px;">
13
- <img id="user-avatar" src="/uploads/avatars/default.png" style="width: 80px; height: 80px; border-radius: 50%; object-fit: cover; border: 3px solid #1abc9c;">
13
+ <img id="user-avatar" src="/api/bank/uploads/avatars/default.png" style="width: 80px; height: 80px; border-radius: 50%; object-fit: cover; border: 3px solid #1abc9c;">
14
14
  </div>
15
15
  <h2 id="user-display">Загрузка...</h2>
16
16
  <p style="text-align: center; color: #bbb;">Всего средств: <span id="total-manny" style="font-weight: bold; color: #1abc9c;">0.00</span> руб.</p>
17
17
  <hr style="border-color: #34495e;">
18
- <a href="/general.html" class="nav-item"><button class="menu-btn" id="general">Главная</button></a>
18
+ <a href="/bank/general.html" class="nav-item"><button class="menu-btn" id="general">Главная</button></a>
19
19
  <a class="nav-item"><button class="menu-btn active" id="acccount">Мои Счета</button></a>
20
- <a href="/transfer.html" class="nav-item"><button class="menu-btn" id="transfer">Перевод средств</button></a>
21
- <a href="/history.html" class="nav-item"><button class="menu-btn" id="history">История транзакций</button></a>
22
- <a href="/credit.html" class="nav-item"><button class="menu-btn" id="credit">Оформить Кредит</button></a>
23
- <a href="/profile.html" class="nav-item"><button class="menu-btn" id="profile">Управление профилем</button></a>
24
- <button class="menu-btn" onclick="location.href='/admin.html'" id="admin-nav" style="display: none; color: #ffc107;">Админ-панель</button>
20
+ <a href="/bank/transfer.html" class="nav-item"><button class="menu-btn" id="transfer">Перевод средств</button></a>
21
+ <a href="/bank/history.html" class="nav-item"><button class="menu-btn" id="history">История транзакций</button></a>
22
+ <a href="/bank/credit.html" class="nav-item"><button class="menu-btn" id="credit">Оформить Кредит</button></a>
23
+ <a href="/bank/profile.html" class="nav-item"><button class="menu-btn" id="profile">Управление профилем</button></a>
24
+ <button class="menu-btn" onclick="location.href='/bank/admin.html'" id="admin-nav" style="display: none; color: #ffc107;">Админ-панель</button>
25
25
  <br><br>
26
26
  <button class="menu-btn btn-danger" id="logoutBtn" style="text-align: center;">Выйти из системы</button>
27
27
  </div>
@@ -39,9 +39,9 @@
39
39
  </div>
40
40
  </div>
41
41
  <script src="https://cdnjs.cloudflare.com/ajax/libs/zxcvbn/4.4.2/zxcvbn.js"></script>
42
- <script src="/js/sweetalert2.js"></script>
42
+ <script src="/api/bank/js/sweetalert2.js"></script>
43
43
  <script src="https://unpkg.com/@popperjs/core@2/dist/umd/popper.min.js"></script>
44
44
  <script src="https://unpkg.com/tippy.js@6/dist/tippy-bundle.umd.js"></script>
45
- <script src="/js/js.js"></script>
45
+ <script src="/api/bank/js/js.js"></script>
46
46
  </body>
47
- </html>
47
+ </html>
package/public/admin.html CHANGED
@@ -39,8 +39,8 @@
39
39
  <body>
40
40
 
41
41
  <div class="container">
42
- <h2>👑 ЦЕНТРАЛЬНЫЙ ПУЛЬТ АДМИНИСТРАТОРА (ROOT)</h2>
43
- <button class="btn" onclick="location.href='/general.html'" style="background:#6c757d;"><- В личный кабинет</button>
42
+ <h2>ЦЕНТРАЛЬНЫЙ ПУЛЬТ АДМИНИСТРАТОРА (ROOT)</h2>
43
+ <button class="btn" onclick="location.href='/bank/general.html'" style="background:#6c757d;"><- В личный кабинет</button>
44
44
 
45
45
  <!-- Интерактивная таблица всех счетов -->
46
46
  <table id="all-accounts-table">
@@ -90,7 +90,7 @@
90
90
  // Загрузка таблицы при старте страницы
91
91
  async function loadAdminDashboard() {
92
92
  try {
93
- const response = await fetch('/api/admin/accounts/all');
93
+ const response = await fetch('/api/bank/admin/accounts/all');
94
94
  const result = await response.json();
95
95
 
96
96
  if (!response.ok || !result.status) {
@@ -128,7 +128,7 @@
128
128
  // Переключение статуса бана/разбана
129
129
  async function toggleAccountStatus(accountId, makeActive) {
130
130
  try {
131
- const response = await fetch(`/api/admin/accounts/${accountId}/status`, {
131
+ const response = await fetch(`/api/bank/admin/accounts/${accountId}/status`, {
132
132
  method: 'POST',
133
133
  headers: {'Content-Type': 'application/json'},
134
134
  body: JSON.stringify({ active: makeActive })
@@ -169,7 +169,7 @@
169
169
 
170
170
  try {
171
171
  // Роут /modify работает через add-manny.js и remove-manny.js, которые НЕ шлют письма по ТЗ
172
- const response = await fetch(`/api/admin/accounts/${accountId}/modify`, {
172
+ const response = await fetch(`/api/bank/admin/accounts/${accountId}/modify`, {
173
173
  method: 'POST',
174
174
  headers: {'Content-Type': 'application/json'},
175
175
  body: JSON.stringify({ amount, type })
@@ -3,25 +3,25 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <title>City-Bank | Кредитование</title>
6
- <link rel="stylesheet" href="/css/style.css">
6
+ <link rel="stylesheet" href="/api/bank/css/style.css">
7
7
  <link rel="stylesheet" href="https://unpkg.com/tippy.js@6/animations/scale.css"/>
8
8
  </head>
9
9
  <body>
10
10
  <div class="main-container">
11
11
  <div class="sidebar">
12
12
  <div style="text-align: center; margin-bottom: 15px;">
13
- <img id="user-avatar" src="/uploads/avatars/default.png" style="width: 80px; height: 80px; border-radius: 50%; object-fit: cover; border: 3px solid #1abc9c;">
13
+ <img id="user-avatar" src="/api/bank/uploads/avatars/default.png" style="width: 80px; height: 80px; border-radius: 50%; object-fit: cover; border: 3px solid #1abc9c;">
14
14
  </div>
15
15
  <h2 id="user-display">Загрузка...</h2>
16
16
  <p style="text-align: center; color: #bbb;">Всего средств: <span id="total-manny" style="font-weight: bold; color: #1abc9c;">0.00</span> руб.</p>
17
17
  <hr style="border-color: #34495e;">
18
- <a href="/general.html" class="nav-item"><button class="menu-btn" id="general">Главная</button></a>
19
- <a href="/accounts.html" class="nav-item"><button class="menu-btn" id="acccount">Мои Счета</button></a>
20
- <a href="/transfer.html" class="nav-item"><button class="menu-btn" id="transfer">Перевод средств</button></a>
21
- <a href="/history.html" class="nav-item"><button class="menu-btn" id="history">История транзакций</button></a>
18
+ <a href="/bank/general.html" class="nav-item"><button class="menu-btn" id="general">Главная</button></a>
19
+ <a href="/bank/accounts.html" class="nav-item"><button class="menu-btn" id="acccount">Мои Счета</button></a>
20
+ <a href="/bank/transfer.html" class="nav-item"><button class="menu-btn" id="transfer">Перевод средств</button></a>
21
+ <a href="/bank/history.html" class="nav-item"><button class="menu-btn" id="history">История транзакций</button></a>
22
22
  <a class="nav-item"><button class="menu-btn active" id="credit">Оформить Кредит</button></a>
23
- <a href="/profile.html" class="nav-item"><button class="menu-btn" id="profile">Управление профилем</button></a>
24
- <button class="menu-btn" onclick="location.href='/admin.html'" id="admin-nav" style="display: none; color: #ffc107;">Админ-панель</button>
23
+ <a href="/bank/profile.html" class="nav-item"><button class="menu-btn" id="profile">Управление профилем</button></a>
24
+ <button class="menu-btn" onclick="location.href='/bank/admin.html'" id="admin-nav" style="display: none; color: #ffc107;">Админ-панель</button>
25
25
  <br><br>
26
26
  <button class="menu-btn btn-danger" id="logoutBtn" style="text-align: center;">Выйти из системы</button>
27
27
  </div>
@@ -82,9 +82,9 @@
82
82
  </div>
83
83
  </div>
84
84
  <script src="https://cdnjs.cloudflare.com/ajax/libs/zxcvbn/4.4.2/zxcvbn.js"></script>
85
- <script src="/js/sweetalert2.js"></script>
85
+ <script src="/api/bank/js/sweetalert2.js"></script>
86
86
  <script src="https://unpkg.com/@popperjs/core@2/dist/umd/popper.min.js"></script>
87
87
  <script src="https://unpkg.com/tippy.js@6/dist/tippy-bundle.umd.js"></script>
88
- <script src="/js/js.js"></script>
88
+ <script src="/api/bank/js/js.js"></script>
89
89
  </body>
90
90
  </html>
@@ -58,4 +58,6 @@
58
58
  .tippy-box[data-theme~='user-info']{
59
59
  background-color: rgba(240, 248, 255, 0.747);
60
60
  border: 1px solid rgb(0, 0, 255);
61
- }
61
+ }
62
+
63
+ :disabled{cursor:not-allowed;}
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8">
5
5
  <title>City-Bank | Главная</title>
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1">
7
- <link rel="stylesheet" href="/css/style.css">
7
+ <link rel="stylesheet" href="/api/bank/css/style.css">
8
8
  <link rel="stylesheet" href="https://unpkg.com/tippy.js@6/animations/scale.css"/>
9
9
  <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/toastify-js/src/toastify.min.css">
10
10
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/toastify-js"></script>
@@ -19,12 +19,12 @@
19
19
  <p style="text-align: center; color: #bbb;">Всего средств: <span id="total-manny" style="font-weight: bold; color: #1abc9c;">0.00</span> руб.</p>
20
20
  <hr style="border-color: #34495e;">
21
21
  <a class="nav-item"><button class="menu-btn active" id="general">Главная</button></a>
22
- <a href="/accounts.html" class="nav-item"><button class="menu-btn" id="acccount">Мои Счета</button></a>
23
- <a href="/transfer.html" class="nav-item"><button class="menu-btn" id="transfer">Перевод средств</button></a>
24
- <a href="/history.html" class="nav-item"><button class="menu-btn" id="history">История транзакций</button></a>
25
- <a href="/credit.html" class="nav-item"><button class="menu-btn" id="credit">Оформить Кредит</button></a>
26
- <a href="/profile.html" class="nav-item"><button class="menu-btn" id="profile">Управление профилем</button></a>
27
- <button class="menu-btn" onclick="location.href='/admin.html'" id="admin-nav" style="display: none; color: #ffc107;">Админ-панель</button>
22
+ <a href="/bank/accounts.html" class="nav-item"><button class="menu-btn" id="acccount">Мои Счета</button></a>
23
+ <a href="/bank/transfer.html" class="nav-item"><button class="menu-btn" id="transfer">Перевод средств</button></a>
24
+ <a href="/bank/history.html" class="nav-item"><button class="menu-btn" id="history">История транзакций</button></a>
25
+ <a href="/bank/credit.html" class="nav-item"><button class="menu-btn" id="credit">Оформить Кредит</button></a>
26
+ <a href="/bank/profile.html" class="nav-item"><button class="menu-btn" id="profile">Управление профилем</button></a>
27
+ <button class="menu-btn" onclick="location.href='/bank/admin.html'" id="admin-nav" style="display: none; color: #ffc107;">Админ-панель</button>
28
28
  <br><br>
29
29
  <button class="menu-btn btn-danger" id="logoutBtn" style="text-align: center;">Выйти из системы</button>
30
30
  </div>
@@ -32,14 +32,14 @@
32
32
  <div class="container">
33
33
  <div class="container-center">
34
34
  <div style="text-align: center; margin-bottom: 15px;" onclick="uploadAvatar()">
35
- <img id="user-avatar2" src="/uploads/avatars/default.png" style="width: 250px; height: 250px; border-radius: 50%; object-fit: cover; border: 3px solid #1abc9c;">
35
+ <img id="user-avatar2" src="/api/bank/uploads/avatars/default.png" style="width: 250px; height: 250px; border-radius: 50%; object-fit: cover; border: 3px solid #1abc9c;">
36
36
  </div>
37
37
  <h1 id="user-display-page">Загрузка...</h1>
38
38
  <!--и так далее-->
39
39
  <p>Подать запрос в поддержку</p>
40
40
  <form action="/help-message" method="post" class="help_msg-form">
41
41
  <input type="text" name="hm" placeholder="Здраствуйте. Я .. хочу попросить помощи. У меня не работает ... . Спасибо">
42
- <input type="submit" value="Отправить">
42
+ <input disabled type="submit" value="Отправить">
43
43
  </form>
44
44
  <footer>
45
45
  <p style="color: lightslategray;">Банк ©2026</p>
@@ -48,9 +48,9 @@
48
48
  </div>
49
49
  </div>
50
50
  <script src="https://cdnjs.cloudflare.com/ajax/libs/zxcvbn/4.4.2/zxcvbn.js"></script>
51
- <script src="/js/sweetalert2.js"></script>
51
+ <script src="/api/bank/js/sweetalert2.js"></script>
52
52
  <script src="https://unpkg.com/@popperjs/core@2/dist/umd/popper.min.js"></script>
53
53
  <script src="https://unpkg.com/tippy.js@6/dist/tippy-bundle.umd.js"></script>
54
- <script src="/js/js.js"></script>
54
+ <script src="/api/bank/js/js.js"></script>
55
55
  </body>
56
56
  </html>
@@ -3,32 +3,32 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <title>City-Bank | История</title>
6
- <link rel="stylesheet" href="/css/style.css">
6
+ <link rel="stylesheet" href="/api/bank/css/style.css">
7
7
  <link rel="stylesheet" href="https://unpkg.com/tippy.js@6/animations/scale.css"/>
8
8
  </head>
9
9
  <body>
10
10
  <div class="main-container">
11
11
  <div class="sidebar">
12
12
  <div style="text-align: center; margin-bottom: 15px;">
13
- <img id="user-avatar" src="/uploads/avatars/default.png" style="width: 80px; height: 80px; border-radius: 50%; object-fit: cover; border: 3px solid #1abc9c;">
13
+ <img id="user-avatar" src="/api/bank/uploads/avatars/default.png" style="width: 80px; height: 80px; border-radius: 50%; object-fit: cover; border: 3px solid #1abc9c;">
14
14
  </div>
15
15
  <h2 id="user-display">Загрузка...</h2>
16
16
  <p style="text-align: center; color: #bbb;">Всего средств: <span id="total-manny" style="font-weight: bold; color: #1abc9c;">0.00</span> руб.</p>
17
17
  <hr style="border-color: #34495e;">
18
- <a href="/general.html" class="nav-item"><button class="menu-btn" id="general">Главная</button></a>
19
- <a href="/accounts.html" class="nav-item"><button class="menu-btn" id="acccount">Мои Счета</button></a>
20
- <a href="/transfer.html" class="nav-item"><button class="menu-btn" id="transfer">Перевод средств</button></a>
18
+ <a href="/bank/general.html" class="nav-item"><button class="menu-btn" id="general">Главная</button></a>
19
+ <a href="/bank/accounts.html" class="nav-item"><button class="menu-btn" id="acccount">Мои Счета</button></a>
20
+ <a href="/bank/transfer.html" class="nav-item"><button class="menu-btn" id="transfer">Перевод средств</button></a>
21
21
  <a class="nav-item"><button class="menu-btn active" id="history">История транзакций</button></a>
22
- <a href="/credit.html" class="nav-item"><button class="menu-btn" id="credit">Оформить Кредит</button></a>
23
- <a href="/profile.html" class="nav-item"><button class="menu-btn" id="profile">Управление профилем</button></a>
24
- <button class="menu-btn" onclick="location.href='/admin.html'" id="admin-nav" style="display: none; color: #ffc107;">Админ-панель</button>
22
+ <a href="/bank/credit.html" class="nav-item"><button class="menu-btn" id="credit">Оформить Кредит</button></a>
23
+ <a href="/bank/profile.html" class="nav-item"><button class="menu-btn" id="profile">Управление профилем</button></a>
24
+ <button class="menu-btn" onclick="location.href='/bank/admin.html'" id="admin-nav" style="display: none; color: #ffc107;">Админ-панель</button>
25
25
  <br><br>
26
26
  <button class="menu-btn btn-danger" id="logoutBtn" style="text-align: center;">Выйти из системы</button>
27
27
  </div>
28
28
  <div class="container">
29
29
  <div class="container-center">
30
30
  <div style="text-align: center; margin-bottom: 15px;">
31
- <img id="user-avatar2" src="/uploads/avatars/default.png" style="width: 250px; height: 250px; border-radius: 50%; object-fit: cover; border: 3px solid #1abc9c;">
31
+ <img id="user-avatar2" src="/api/bank/uploads/avatars/default.png" style="width: 250px; height: 250px; border-radius: 50%; object-fit: cover; border: 3px solid #1abc9c;">
32
32
  </div>
33
33
  <h3>История финансовых операций</h3>
34
34
  <div class="card">
@@ -57,9 +57,9 @@
57
57
  <h1>hello</h1>
58
58
  </dialog>
59
59
  <script src="https://cdnjs.cloudflare.com/ajax/libs/zxcvbn/4.4.2/zxcvbn.js"></script>
60
- <script src="/js/sweetalert2.js"></script>
60
+ <script src="/api/bank/js/sweetalert2.js"></script>
61
61
  <script src="https://unpkg.com/@popperjs/core@2/dist/umd/popper.min.js"></script>
62
62
  <script src="https://unpkg.com/tippy.js@6/dist/tippy-bundle.umd.js"></script>
63
- <script src="/js/js.js"></script>
63
+ <script src="/api/bank/js/js.js"></script>
64
64
  </body>
65
65
  </html>
package/public/home.html CHANGED
@@ -297,8 +297,8 @@
297
297
  <header class="bank-navbar">
298
298
  <div class="logo">GAME-<span>BANK</span></div>
299
299
  <div class="auth-buttons">
300
- <a href="/login.html"><button class="btn-auth btn-login">Войти</button></a>
301
- <a href="/register.html"><button class="btn-auth btn-register">Регистрация</button></a>
300
+ <a href="/bank/login.html"><button class="btn-auth btn-login">Войти</button></a>
301
+ <a href="/bank/register.html"><button class="btn-auth btn-register">Регистрация</button></a>
302
302
  </div>
303
303
  </header>
304
304
  <main class="main-content">
package/public/js/js.js CHANGED
@@ -1,20 +1,13 @@
1
- //import Toastifyt from 'https://cdn.jsdelivr.net/npm/toastify-js';
2
1
  const toastifyScript = document.createElement('script');
3
2
  toastifyScript.src = 'https://cdn.jsdelivr.net/npm/toastify-js';
4
3
  document.head.append(toastifyScript);
5
4
  let currentUsername = "";
6
-
7
5
  function showTab(tabId) {
8
6
  document.querySelectorAll('.section').forEach(s => s.classList.remove('active'));
9
7
  document.querySelectorAll('.menu-btn').forEach(b => b.classList.remove('active'));
10
8
  document.getElementById(tabId).classList.add('active');
11
9
  event.target.classList.add('active');
12
10
  }
13
-
14
-
15
-
16
-
17
-
18
11
  window.tippy('#general', {
19
12
  content: "Главная",
20
13
  placement:'top-end',
@@ -57,22 +50,9 @@ let currentUsername = "";
57
50
  animation:'scale-extreme',
58
51
  theme:"light"
59
52
  });
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
53
  async function loadData() {
74
54
  try {
75
- let response = await fetch('/api/accounts/my');
55
+ let response = await fetch('/api/bank/accounts/my');
76
56
  if (response.status === 401 || response.status === 403) {
77
57
  window.Swal.fire({
78
58
  title: 'Внимание!',
@@ -83,11 +63,11 @@ let currentUsername = "";
83
63
  confirmButtonColor: '#3085d6',
84
64
  background:'#d6cb3089'
85
65
  });
86
- window.location.href = '/login.html';
66
+ window.location.href = '/bank/login.html';
87
67
  return;
88
68
  }
89
69
  let result = await response.json();
90
- let mannyRes = await fetch('/api/users/my-total-manny');
70
+ let mannyRes = await fetch('/api/bank/users/my-total-manny');
91
71
  let mannyData = await mannyRes.json();
92
72
  currentUsername = mannyData.username;
93
73
  const userDisplay = document.getElementById('user-display');
@@ -152,7 +132,7 @@ let currentUsername = "";
152
132
  }
153
133
  });
154
134
  }
155
- let profileRes = await fetch('/api/users/profile');
135
+ let profileRes = await fetch('/api/bank/users/profile');
156
136
  let profileData = await profileRes.json();
157
137
  const userAvatar = document.getElementById('user-avatar');
158
138
  window.tippy("#user-avatar", {
@@ -185,38 +165,11 @@ let currentUsername = "";
185
165
  });
186
166
  }
187
167
  }
188
-
189
-
190
-
191
-
192
-
193
-
194
-
195
-
196
-
197
-
198
-
199
-
200
-
201
-
202
-
203
-
204
-
205
-
206
-
207
-
208
-
209
-
210
-
211
-
212
-
213
-
214
-
215
168
  async function openCreateAccountModal() {
216
169
  const pin = await window.Swal.fire({title: 'Создание щёта', text: 'Введите надёжный пин-код!', icon: 'question', iconColor:"blue", input:"number", inputAttributes: { autocapitalize: "off" }, preConfirm:async(pincode)=>{return pincode}, confirmButtonText: 'ОК', confirmButtonColor: '#3085d6', background:'#ffffffaf'})
217
170
  if (!pin.value) return;
218
171
  const fa = await Swal.fire({title: 'Создание щёта', text: 'Включить индивидуальную 2FA-защиту транзакций для этого счета?', icon: 'question', iconColor:"blue", showCancelButton: true, confirmButtonColor: '#3085d6', cancelButtonColor: '#3085d6', confirmButtonText: 'Да, включить', cancelButtonText: 'Нет, не включать'}).then((result) => {return result;});
219
- const res = await fetch('/api/accounts', {
172
+ const res = await fetch('/api/bank/accounts', {
220
173
  method: 'POST',
221
174
  headers: {'Content-Type': 'application/json'},
222
175
  body: JSON.stringify({ pinCode: pin.value, enableAccount2FA: fa.isConfirmed })
@@ -253,7 +206,7 @@ let currentUsername = "";
253
206
  const fa = await Swal.fire({title: 'Перевод', text: 'Вы подтверждаете перевод?', icon: 'question', iconColor:"blue", showCancelButton: true, confirmButtonColor: '#3085d6', cancelButtonColor: '#3085d6', confirmButtonText: 'Да, перевести', cancelButtonText: 'Нет, не переводить'}).then((result) => {return result;});
254
207
  if(!fa.isConfirmed) return
255
208
 
256
- const res = await fetch('/api/accounts/transfer', {
209
+ const res = await fetch('/api/bank/accounts/transfer', {
257
210
  method: 'POST',
258
211
  headers: {'Content-Type': 'application/json'},
259
212
  body: JSON.stringify({ fromId, toId, amount, pinCode })
@@ -275,20 +228,13 @@ let currentUsername = "";
275
228
  console.error("Ошибка ["+data.statusCode+"]: " + data.message);
276
229
  }
277
230
  }
278
-
279
-
280
-
281
-
282
-
283
-
284
-
285
231
  async function applyForCredit() {
286
232
  const targetAccountId = document.getElementById('credit-target').value;
287
233
  const amount = document.getElementById('credit-amount').value;
288
234
  const paymentsCount = document.getElementById('credit-payments').value;
289
235
  const autoWithdrawal = document.getElementById('credit-auto').checked;
290
236
  const pinCode = document.getElementById('credit-pin').value;
291
- const res = await fetch('/api/accounts/credit', {
237
+ const res = await fetch('/api/bank/accounts/credit', {
292
238
  method: 'POST',
293
239
  headers: {'Content-Type': 'application/json'},
294
240
  body: JSON.stringify({
@@ -347,48 +293,26 @@ document.getElementById("logoutBtn").addEventListener("click", async () => {
347
293
  await Toastify({ text: `Выход из аккаунта`, duration: 3000, style: { background: "rgb(245, 128, 11)" }}).showToast();
348
294
 
349
295
  try {
350
- await fetch('/api/users/logout', { method: 'POST' });
296
+ await fetch('/api/bank/users/logout', { method: 'POST' });
351
297
  } catch (e) {
352
298
  console.error('Ошибка сети при логауте:', e.message);
353
299
  }
354
- window.location.href = '/home.html';
300
+ window.location.href = '/bank/home.html';
355
301
  });
356
-
357
-
358
-
359
-
360
-
361
-
362
-
363
-
364
-
365
-
366
-
367
-
368
-
369
-
370
-
371
-
372
-
373
302
  window.onload = loadData;
374
303
  let user2FaActive = false;
375
-
376
304
  async function syncProfileSectionData() {
377
305
  try {
378
- const response = await fetch('/api/users/profile');
379
-
380
- // 🔑 ЗАЩИТА: Если бэкенд вернул ошибку (не 200 OK), не пытаемся парсить JSON
306
+ const response = await fetch('/api/bank/users/profile/settings');
381
307
  if (!response.ok) {
382
308
  console.warn("⚠️ [City-bank] Не удалось загрузить данные профиля, сервер вернул статус:", response.status);
383
309
  return;
384
310
  }
385
-
386
311
  const result = await response.json();
387
312
  if (result.status && result.user) {
388
313
  if (result.user.avatar) {
389
314
  document.getElementById('user-avatar').src = result.user.avatar;
390
- }
391
-
315
+ }
392
316
  user2FaActive = result.user.two_fa_status;
393
317
  const statusText = document.getElementById('2fa-current-status');
394
318
  const toggleBtn = document.getElementById('btn-toggle-2fa');
@@ -418,7 +342,7 @@ document.getElementById("logoutBtn").addEventListener("click", async () => {
418
342
  formData.append('avatar', fileInput.files[0]);
419
343
 
420
344
  try {
421
- const res = await fetch('/api/users/avatar', {
345
+ const res = await fetch('/api/bank/users/avatar', {
422
346
  method: 'POST',
423
347
  body: formData
424
348
  });
@@ -454,7 +378,7 @@ document.getElementById("logoutBtn").addEventListener("click", async () => {
454
378
  if (!totpCode) return;
455
379
  }
456
380
  try {
457
- const res = await fetch('/api/users/change-password', {
381
+ const res = await fetch('/api/bank/users/change-password', {
458
382
  method: 'POST',
459
383
  headers: {'Content-Type': 'application/json'},
460
384
  body: JSON.stringify({ oldPassword, newPassword, totpCode })
@@ -485,7 +409,7 @@ document.getElementById("logoutBtn").addEventListener("click", async () => {
485
409
  }
486
410
 
487
411
  try {
488
- const res = await fetch('/api/users/change-gmail', {
412
+ const res = await fetch('/api/bank/users/change-gmail', {
489
413
  method: 'POST',
490
414
  headers: {'Content-Type': 'application/json'},
491
415
  body: JSON.stringify({ newGmail })
@@ -510,7 +434,7 @@ document.getElementById("logoutBtn").addEventListener("click", async () => {
510
434
  }
511
435
  }
512
436
  async function toggleSystem2FA() {
513
- const url = user2FaActive ? '/api/users/disable-2fa' : '/api/users/enable-2fa';
437
+ const url = user2FaActive ? '/api/bank/users/disable-2fa' : '/api/bank/users/enable-2fa';
514
438
  try {
515
439
  const res = await fetch(url, { method: 'POST' });
516
440
  const data = await res.json();
@@ -547,7 +471,7 @@ document.getElementById("logoutBtn").addEventListener("click", async () => {
547
471
  const deleteAccountStatus = await Swal.fire({title: 'Удаление щёта', text: 'Вы действительно хотите удалить щёт?', icon: 'warning', iconColor:"orange", showCancelButton: true, confirmButtonColor: '#d63030', cancelButtonColor: '#46d630', confirmButtonText: 'Да, удалить', cancelButtonText: 'Отмена'}).then((result) => {return result;});
548
472
  if (!deleteAccountStatus.isConfirmed) return;
549
473
  try {
550
- const response = await fetch(`/api/accounts/${accountId}`, {
474
+ const response = await fetch(`/api/bank/accounts/${accountId}`, {
551
475
  method: 'DELETE'
552
476
  });
553
477
  if (!response.ok) {
@@ -583,7 +507,7 @@ document.getElementById("logoutBtn").addEventListener("click", async () => {
583
507
  }
584
508
  async function loadTransactionLogs() {
585
509
  try {
586
- const response = await fetch('/api/accounts/my-logs');
510
+ const response = await fetch('/api/bank/accounts/my-logs');
587
511
  if (!response.ok) return;
588
512
  const result = await response.json();
589
513
  const tbody = document.querySelector('#table-logs tbody');
@@ -658,7 +582,7 @@ document.getElementById("logoutBtn").addEventListener("click", async () => {
658
582
  }
659
583
 
660
584
  // 3. Отправляем fetch-запрос на бэкенд-роут игрового банка
661
- const response = await fetch('/api/account/create-credit', {
585
+ const response = await fetch('/api/bank/accounts/credit', {
662
586
  method: 'POST',
663
587
  headers: {
664
588
  'Content-Type': 'application/json'
@@ -683,7 +607,7 @@ document.getElementById("logoutBtn").addEventListener("click", async () => {
683
607
  if (result.success) {
684
608
  Swal.fire('Успех!', result.message || 'Кредит успешно оформлен', 'success').then(() => {
685
609
  // Перенаправляем пользователя на страницу счетов, чтобы увидеть обновленный баланс
686
- location.href = '/accounts';
610
+ location.href = '/bank/accounts.html';
687
611
  });
688
612
  } else {
689
613
  Swal.fire('Ошибка оформления', result.error || 'Не удалось выдать кредит', 'error');
package/public/login.html CHANGED
@@ -34,7 +34,7 @@
34
34
 
35
35
  <div id="login-error" class="error"></div>
36
36
  <button class="btn" onclick="submitLogin()">Войти в кабинет</button>
37
- <p style="text-align: center; font-size: 14px; margin-top: 15px;"><a href="/register.html">Создать аккаунт</a></p>
37
+ <p style="text-align: center; font-size: 14px; margin-top: 15px;"><a href="/bank/register.html">Создать аккаунт</a></p>
38
38
  </div>
39
39
 
40
40
  <script>
@@ -46,7 +46,7 @@
46
46
  errBlock.style.display = 'none';
47
47
 
48
48
  try {
49
- const response = await fetch('/api/users/login', {
49
+ const response = await fetch('/api/bank/users/login', {
50
50
  method: 'POST',
51
51
  headers: {'Content-Type': 'application/json'},
52
52
  body: JSON.stringify({ name, password: pass, totpCode: totp || null })
@@ -54,7 +54,7 @@
54
54
  const result = await response.json();
55
55
 
56
56
  if (response.ok && result.status === true) {
57
- window.location.href = 'general.html';
57
+ window.location.href = '/bank/general.html';
58
58
  } else if (result.require2FA) {
59
59
  document.getElementById('totp-block').style.display = 'block';
60
60
  errBlock.innerText = result.message;
@@ -3,25 +3,25 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <title>City-Bank | Профиль</title>
6
- <link rel="stylesheet" href="/css/style.css">
6
+ <link rel="stylesheet" href="/api/bank/css/style.css">
7
7
  <link rel="stylesheet" href="https://unpkg.com/tippy.js@6/animations/scale.css"/>
8
8
  </head>
9
9
  <body>
10
10
  <div class="main-container">
11
11
  <div class="sidebar">
12
12
  <div style="text-align: center; margin-bottom: 15px;">
13
- <img id="user-avatar" src="/uploads/avatars/default.png" style="width: 80px; height: 80px; border-radius: 50%; object-fit: cover; border: 3px solid #1abc9c;">
13
+ <img id="user-avatar" src="/api/bank/uploads/avatars/default.png" style="width: 80px; height: 80px; border-radius: 50%; object-fit: cover; border: 3px solid #1abc9c;">
14
14
  </div>
15
15
  <h2 id="user-display">Загрузка...</h2>
16
16
  <p style="text-align: center; color: #bbb;">Всего средств: <span id="total-manny" style="font-weight: bold; color: #1abc9c;">0.00</span> руб.</p>
17
17
  <hr style="border-color: #34495e;">
18
- <a href="/general.html" class="nav-item"><button class="menu-btn" id="general">Главная</button></a>
19
- <a href="/accounts.html" class="nav-item"><button class="menu-btn" id="acccount">Мои Счета</button></a>
20
- <a href="/transfer.html" class="nav-item"><button class="menu-btn" id="transfer">Перевод средств</button></a>
21
- <a href="/history.html" class="nav-item"><button class="menu-btn" id="history">История транзакций</button></a>
22
- <a href="/credit.html" class="nav-item"><button class="menu-btn" id="credit">Оформить Кредит</button></a>
18
+ <a href="/bank/general.html" class="nav-item"><button class="menu-btn" id="general">Главная</button></a>
19
+ <a href="/bank/accounts.html" class="nav-item"><button class="menu-btn" id="acccount">Мои Счета</button></a>
20
+ <a href="/bank/transfer.html" class="nav-item"><button class="menu-btn" id="transfer">Перевод средств</button></a>
21
+ <a href="/bank/history.html" class="nav-item"><button class="menu-btn" id="history">История транзакций</button></a>
22
+ <a href="/bank/credit.html" class="nav-item"><button class="menu-btn" id="credit">Оформить Кредит</button></a>
23
23
  <a class="nav-item"><button class="menu-btn active" id="profile">Управление профилем</button></a>
24
- <button class="menu-btn" onclick="location.href='/admin.html'" id="admin-nav" style="display: none; color: #ffc107;">Админ-панель</button>
24
+ <button class="menu-btn" onclick="location.href='/bank/admin.html'" id="admin-nav" style="display: none; color: #ffc107;">Админ-панель</button>
25
25
  <br><br>
26
26
  <button class="menu-btn btn-danger" id="logoutBtn" style="text-align: center;">Выйти из системы</button>
27
27
  </div>
@@ -73,9 +73,9 @@
73
73
  </div>
74
74
  </div>
75
75
  <script src="https://cdnjs.cloudflare.com/ajax/libs/zxcvbn/4.4.2/zxcvbn.js"></script>
76
- <script src="/js/sweetalert2.js"></script>
76
+ <script src="/api/bank/js/sweetalert2.js"></script>
77
77
  <script src="https://unpkg.com/@popperjs/core@2/dist/umd/popper.min.js"></script>
78
78
  <script src="https://unpkg.com/tippy.js@6/dist/tippy-bundle.umd.js"></script>
79
- <script src="/js/js.js"></script>
79
+ <script src="/api/bank/js/js.js"></script>
80
80
  </body>
81
81
  </html>
@@ -239,7 +239,7 @@
239
239
  }
240
240
 
241
241
  try {
242
- const response = await fetch(`/api/users/check-nik?name=${encodeURIComponent(nikInput)}`);
242
+ const response = await fetch(`/api/bank/users/check-nik?name=${encodeURIComponent(nikInput)}`);
243
243
  const result = await response.json();
244
244
 
245
245
  if (result.status === true && result.statusCode === 1) {
@@ -267,7 +267,7 @@
267
267
  }
268
268
 
269
269
  try {
270
- const response = await fetch(`/api/users/check-gmail?gmail=${encodeURIComponent(gmailInput)}`);
270
+ const response = await fetch(`/api/bank/users/check-gmail?gmail=${encodeURIComponent(gmailInput)}`);
271
271
  const result = await response.json();
272
272
 
273
273
  if (result.status === true && result.statusCode === 1) {
@@ -317,7 +317,7 @@
317
317
  nextBtn.innerText = "Проверить токен 2FA";
318
318
 
319
319
  try {
320
- const response = await fetch('/api/users/generate-temporary-2fa', {
320
+ const response = await fetch('/api/bank/users/generate-temporary-2fa', {
321
321
  method: 'POST',
322
322
  headers: {'Content-Type': 'application/json'},
323
323
  body: JSON.stringify({ name: registrationPayload.name || document.getElementById('reg-nik').value.trim() })
@@ -376,7 +376,7 @@
376
376
  }
377
377
 
378
378
  try {
379
- const response = await fetch('/api/users/verify-temporary-2fa', {
379
+ const response = await fetch('/api/bank/users/verify-temporary-2fa', {
380
380
  method: 'POST',
381
381
  headers: {'Content-Type': 'application/json'},
382
382
  body: JSON.stringify({
@@ -418,7 +418,7 @@
418
418
  registrationPayload.userSurname = surname;
419
419
 
420
420
  try {
421
- const response = await fetch('/api/users/register', {
421
+ const response = await fetch('/api/bank/users/register', {
422
422
  method: 'POST',
423
423
  headers: {'Content-Type': 'application/json'},
424
424
  body: JSON.stringify(registrationPayload)
@@ -426,8 +426,8 @@
426
426
  const result = await response.json();
427
427
 
428
428
  if (result.status === true && result.statusCode === 1) {
429
- alert("🎉 Регистрация успешно завершена! Проверьте вашу почту для получения паролей и токенов.");
430
- window.location.href = '/login.html';
429
+ alert("Регистрация успешно завершена! Проверьте вашу почту для получения паролей и токенов.");
430
+ window.location.href = '/bank/login.html';
431
431
  } else {
432
432
  errBlock.innerText = result.message || "Внутренняя ошибка сервера";
433
433
  errBlock.style.display = 'block';
@@ -3,25 +3,25 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <title>City-Bank | Переводы</title>
6
- <link rel="stylesheet" href="/css/style.css">
6
+ <link rel="stylesheet" href="/api/bank/css/style.css">
7
7
  <link rel="stylesheet" href="https://unpkg.com/tippy.js@6/animations/scale.css"/>
8
8
  </head>
9
9
  <body>
10
10
  <div class="main-container">
11
11
  <div class="sidebar">
12
12
  <div style="text-align: center; margin-bottom: 15px;">
13
- <img id="user-avatar" src="/uploads/avatars/default.png" style="width: 80px; height: 80px; border-radius: 50%; object-fit: cover; border: 3px solid #1abc9c;">
13
+ <img id="user-avatar" src="/api/bank/uploads/avatars/default.png" style="width: 80px; height: 80px; border-radius: 50%; object-fit: cover; border: 3px solid #1abc9c;">
14
14
  </div>
15
15
  <h2 id="user-display">Загрузка...</h2>
16
16
  <p style="text-align: center; color: #bbb;">Всего средств: <span id="total-manny" style="font-weight: bold; color: #1abc9c;">0.00</span> руб.</p>
17
17
  <hr style="border-color: #34495e;">
18
- <a href="/general.html" class="nav-item"><button class="menu-btn" id="general">Главная</button></a>
19
- <a href="/accounts.html" class="nav-item"><button class="menu-btn" id="acccount">Мои Счета</button></a>
18
+ <a href="/bank/general.html" class="nav-item"><button class="menu-btn" id="general">Главная</button></a>
19
+ <a href="/bank/accounts.html" class="nav-item"><button class="menu-btn" id="acccount">Мои Счета</button></a>
20
20
  <a class="nav-item"><button class="menu-btn active" id="transfer">Перевод средств</button></a>
21
- <a href="/history.html" class="nav-item"><button class="menu-btn" id="history">История транзакций</button></a>
22
- <a href="/credit.html" class="nav-item"><button class="menu-btn" id="credit">Оформить Кредит</button></a>
23
- <a href="/profile.html" class="nav-item"><button class="menu-btn" id="profile">Управление профилем</button></a>
24
- <button class="menu-btn" onclick="location.href='/admin.html'" id="admin-nav" style="display: none; color: #ffc107;">Админ-панель</button>
21
+ <a href="/bank/history.html" class="nav-item"><button class="menu-btn" id="history">История транзакций</button></a>
22
+ <a href="/bank/credit.html" class="nav-item"><button class="menu-btn" id="credit">Оформить Кредит</button></a>
23
+ <a href="/bank/profile.html" class="nav-item"><button class="menu-btn" id="profile">Управление профилем</button></a>
24
+ <button class="menu-btn" onclick="location.href='/bank/admin.html'" id="admin-nav" style="display: none; color: #ffc107;">Админ-панель</button>
25
25
  <br><br>
26
26
  <button class="menu-btn btn-danger" id="logoutBtn" style="text-align: center;">Выйти из системы</button>
27
27
  </div>
@@ -54,9 +54,9 @@
54
54
  </div>
55
55
  </div>
56
56
  </div>
57
- <script src="/js/sweetalert2.js"></script>
57
+ <script src="/api/bank/js/sweetalert2.js"></script>
58
58
  <script src="https://unpkg.com/@popperjs/core@2/dist/umd/popper.min.js"></script>
59
59
  <script src="https://unpkg.com/tippy.js@6/dist/tippy-bundle.umd.js"></script>
60
- <script src="/js/js.js"></script>
60
+ <script src="/api/bank/js/js.js"></script>
61
61
  </body>
62
62
  </html>
package/server/server.js CHANGED
@@ -5,6 +5,7 @@ const User = require(path.join(__dirname, '..', 'database', 'models', 'User.js')
5
5
  const Account = require(path.join(__dirname, '..', 'database', 'models', 'Account.js'));
6
6
  const multer = require('multer');
7
7
  const fs = require('fs');
8
+ const express = require("express");
8
9
  const logger = require("custom-color-logs").print;
9
10
  const storage = multer.diskStorage({
10
11
  destination: function (req, file, cb) {
@@ -43,8 +44,10 @@ function verifySession(req, res, next) {
43
44
  return res.status(403).json({ status: false, statusCode: -2, message: 'Сессия устарела. Войдите снова.' });
44
45
  }
45
46
  }
46
- module.exports = function registerRoutes(app) {
47
- app.post('/api/users/generate-temporary-2fa', async (req, res) => {
47
+ module.exports = function registerRoutes() {
48
+ const get = express.Router();
49
+ const post = express.Router();
50
+ post.post('/users/generate-temporary-2fa', async (req, res) => {
48
51
  try {
49
52
  const otplib = require('otplib');
50
53
  const { name } = req.body;
@@ -55,7 +58,7 @@ module.exports = function registerRoutes(app) {
55
58
  return res.status(500).json({ status: false, message: err.message });
56
59
  }
57
60
  })
58
- app.post('/api/users/verify-temporary-2fa', async (req, res) => {
61
+ post.post('/users/verify-temporary-2fa', async (req, res) => {
59
62
  try {
60
63
  const otplib = require('otplib');
61
64
  const { secret, code } = req.body;
@@ -72,39 +75,39 @@ module.exports = function registerRoutes(app) {
72
75
  return res.status(500).json({ status: false, message: err.message });
73
76
  }
74
77
  });
75
- app.post('/api/users/avatar', verifySession, upload.single('avatar'), async (req, res) => {
78
+ post.post('/users/avatar', verifySession, upload.single('avatar'), async (req, res) => {
76
79
  if (!req.file) {
77
80
  return res.status(400).json({ status: false, statusCode: -2, message: 'Файл не загружен' });
78
81
  }
79
- const avatarUrl = `/uploads/avatars/${req.file.filename}`;
82
+ const avatarUrl = `/api/bank/uploads/avatars/${req.file.filename}`;
80
83
  const result = await usersHub.changeAvatar(req.user.name, avatarUrl);
81
84
  return res.json(result);
82
85
  });
83
- app.get('/api/users/profile', verifySession, async (req, res) => {
86
+ post.get('/users/profile', verifySession, async (req, res) => {
84
87
  const user = await User.findByPk(req.user.name, { attributes: ['name', 'user_gmail', 'avatar'] });
85
88
  if (!user) return res.status(404).json({ status: false });
86
89
  return res.json({ status: true, user });
87
90
  });
88
- app.get('/api/users/check-nik', async (req, res) => {
91
+ post.get('/users/check-nik', async (req, res) => {
89
92
  const user = await User.findByPk(req.query.name);
90
93
  if (user) {
91
94
  return res.json({ status: false, statusCode: -20, message: 'Никнейм уже занят!' });
92
95
  }
93
96
  return res.json({ status: true, statusCode: 1 });
94
97
  });
95
- app.get('/api/users/check-gmail', async (req, res) => {
98
+ post.get('/users/check-gmail', async (req, res) => {
96
99
  const user = await User.findOne({ where: { user_gmail: req.query.gmail } });
97
100
  if (user) {
98
101
  return res.json({ status: false, statusCode: -21, message: 'Данный email уже используется!' });
99
102
  }
100
103
  return res.json({ status: true, statusCode: 1 });
101
104
  });
102
- app.post('/api/users/register', async (req, res) => {
105
+ post.post('/users/register', async (req, res) => {
103
106
  const result = await usersHub.registerUser(req.body);
104
107
  if (!result.status) return res.status(400).json(result);
105
108
  return res.status(201).json(result);
106
109
  });
107
- app.post('/api/users/login', async (req, res) => {
110
+ post.post('/users/login', async (req, res) => {
108
111
  const { name, password, totpCode } = req.body;
109
112
  const result = await usersHub.login(name, password, totpCode);
110
113
  if (!result.status) {
@@ -117,20 +120,20 @@ module.exports = function registerRoutes(app) {
117
120
  res.cookie('token', sessionToken, { httpOnly: true, maxAge: 2 * 60 * 60 * 1000 });
118
121
  return res.json(result);
119
122
  });
120
- app.post('/api/users/logout', (req, res) => {
123
+ post.post('/users/logout', (req, res) => {
121
124
  res.clearCookie('token');
122
125
  return res.json({ status: true, statusCode: 1 });
123
126
  });
124
- app.get('/api/users/my-total-manny', verifySession, async (req, res) => {
127
+ post.get('/users/my-total-manny', verifySession, async (req, res) => {
125
128
  const result = await usersHub.mathManny(req.user.name);
126
129
  return res.json({ status: result.status, statusCode: result.statusCode, totalManny: result.totalManny, username: req.user.name });
127
130
  });
128
- app.post('/api/accounts', verifySession, async (req, res) => {
131
+ post.post('/accounts', verifySession, async (req, res) => {
129
132
  const { pinCode, enableAccount2FA } = req.body;
130
133
  const result = await accountsHub.create(req.user.name, pinCode, enableAccount2FA);
131
134
  return res.json(result);
132
135
  });
133
- app.get('/api/accounts/my', verifySession, async (req, res) => {
136
+ post.get('/accounts/my', verifySession, async (req, res) => {
134
137
  try {
135
138
  const myAccounts = await Account.findAll({ where: { user: req.user.name } });
136
139
  return res.json({ status: true, statusCode: 1, accounts: myAccounts });
@@ -138,7 +141,7 @@ module.exports = function registerRoutes(app) {
138
141
  return res.status(500).json({ status: false, statusCode: -10 });
139
142
  }
140
143
  });
141
- app.delete('/api/accounts/:id', verifySession, async (req, res) => {
144
+ post.delete('/accounts/:id', verifySession, async (req, res) => {
142
145
  try {
143
146
  const result = await accountsHub.delete(req.params.id, req.user.name);
144
147
  if (!result.status) {
@@ -154,22 +157,22 @@ module.exports = function registerRoutes(app) {
154
157
  return res.status(500).json({ status: false, statusCode: -10, message: "Внутренняя ошибка сервера" });
155
158
  }
156
159
  });
157
- app.post('/api/accounts/transfer', verifySession, async (req, res) => {
160
+ post.post('/accounts/transfer', verifySession, async (req, res) => {
158
161
  const { fromId, toId, amount, pinCode, totpCode } = req.body;
159
162
  const result = await accountsHub.transfer(fromId, toId, amount, pinCode, totpCode);
160
163
  return res.json(result);
161
164
  });
162
- app.post('/api/accounts/credit', verifySession, async (req, res) => {
165
+ post.post('/accounts/credit', verifySession, async (req, res) => {
163
166
  const { targetAccountId, amount, paymentsCount, autoWithdrawal, pinCode } = req.body;
164
167
  const result = await accountsHub.creatCredit(req.user.name, targetAccountId, amount, pinCode, paymentsCount, autoWithdrawal);
165
168
  return res.json(result);
166
169
  });
167
- app.post('/api/admin/accounts/:id/status', verifySession, async (req, res) => {
170
+ post.post('/admin/accounts/:id/status', verifySession, async (req, res) => {
168
171
  if (req.user.name !== 'root') return res.status(403).json({ status: false, statusCode: -2, message: 'Отказано в доступе' });
169
172
  const result = await accountsHub.changeAccountStatus(req.params.id, req.body.active);
170
173
  return res.json(result);
171
174
  });
172
- app.post('/api/admin/accounts/:id/modify', verifySession, async (req, res) => {
175
+ post.post('/admin/accounts/:id/modify', verifySession, async (req, res) => {
173
176
  if (req.user.name !== 'root') return res.status(403).json({ status: false, statusCode: -2, message: 'Отказано в доступе' });
174
177
  const { amount, type } = req.body;
175
178
  let result;
@@ -180,7 +183,7 @@ module.exports = function registerRoutes(app) {
180
183
  }
181
184
  return res.json(result);
182
185
  });
183
- app.get('/api/admin/accounts/all', verifySession, async (req, res) => {
186
+ post.get('/admin/accounts/all', verifySession, async (req, res) => {
184
187
  if (req.user.name !== 'root') return res.status(403).json({ status: false, statusCode: -2, message: 'Отказано в доступе' });
185
188
  try {
186
189
  const allAccounts = await Account.findAll({ order: [['id', 'ASC']] });
@@ -189,7 +192,7 @@ module.exports = function registerRoutes(app) {
189
192
  return res.status(500).json({ status: false, statusCode: -10 });
190
193
  }
191
194
  });
192
- app.get('/api/users/profile', verifySession, async (req, res) => {
195
+ post.get('/users/profile/settings', verifySession, async (req, res) => {
193
196
  try {
194
197
  const user = await User.findByPk(req.user.name, { attributes: ['name', 'user_gmail', 'two_fa_status', 'avatar'] });
195
198
  if (!user) return res.status(404).json({ status: false, message: 'Юзер не найден' });
@@ -198,19 +201,19 @@ module.exports = function registerRoutes(app) {
198
201
  return res.status(500).json({ status: false, message: 'Внутренняя ошибка бэка' });
199
202
  }
200
203
  });
201
- app.post('/api/users/enable-2fa', verifySession, async (req, res) => {
204
+ post.post('/users/enable-2fa', verifySession, async (req, res) => {
202
205
  const result = await usersHub.enable2FA(req.user.name);
203
206
  return res.json(result);
204
207
  });
205
- app.post('/api/users/disable-2fa', verifySession, async (req, res) => {
208
+ post.post('/users/disable-2fa', verifySession, async (req, res) => {
206
209
  const result = await usersHub.disable2FA(req.user.name);
207
210
  return res.json(result);
208
211
  });
209
- app.get('/api/accounts/my-logs', verifySession, async (req, res) => {
212
+ post.get('/accounts/my-logs', verifySession, async (req, res) => {
210
213
  const result = await accountsHub.getLogs(req.user.name);
211
214
  return res.json(result);
212
215
  });
213
- app.post('/api/terminal/register', async(req, res)=>{
216
+ post.post('/terminal/register', async(req, res)=>{
214
217
  if(!req.body) return res.sendStatus(400)
215
218
  const id = req.body.id;
216
219
  const pincode = req.body.pincode;
@@ -219,13 +222,13 @@ module.exports = function registerRoutes(app) {
219
222
  if(!result.status) return res.sendStatus(422)
220
223
  return res.sendStatus(200);
221
224
  });
222
- app.post('/api/terminal/transfer', async(req, res)=>{
225
+ post.post('/terminal/transfer', async(req, res)=>{
223
226
  const card = req.body.card;
224
227
  const to = req.body.to;
225
228
  const pincode = req.body.pincode;
226
- const manny = req.body.pinCode;
229
+ const manny = req.body.manny;
227
230
  const result = await accountsHub.cardTransfer(card, to, manny, pincode)
228
231
  });
229
- return app;
232
+ return {GET:get, POST:post};
230
233
  };
231
234
  module.exports.verifySession = verifySession;