From 0e6103f1383602befa6d1bca625fb5e1d33ea1e5 Mon Sep 17 00:00:00 2001 From: Danil-Bodry Date: Wed, 6 May 2026 21:15:12 +0300 Subject: [PATCH] R.I.P me........ --- frontend/src/components/Layout/AppLayout.vue | 17 + frontend/src/router/index.ts | 6 + frontend/src/views/OLAPConstructor.vue | 938 ++++++++++++++++++ iiko-app.dev.xserver.su.nginx.conf | 32 - .../su/xserver/iikocon/iiko/IikoHandler.java | 2 +- .../xserver/iikocon/test/CodeGenerator.java | 24 + .../xserver/iikocon/test/DateRangeSetup.java | 9 + .../su/xserver/iikocon/test/TestMail.java | 198 ++++ 8 files changed, 1193 insertions(+), 33 deletions(-) create mode 100644 frontend/src/views/OLAPConstructor.vue create mode 100644 src/main/java/su/xserver/iikocon/test/CodeGenerator.java create mode 100644 src/main/java/su/xserver/iikocon/test/TestMail.java diff --git a/frontend/src/components/Layout/AppLayout.vue b/frontend/src/components/Layout/AppLayout.vue index aa825c5..bdf9e7a 100644 --- a/frontend/src/components/Layout/AppLayout.vue +++ b/frontend/src/components/Layout/AppLayout.vue @@ -93,6 +93,23 @@ {{ t('app.olapColumns') }} + + + + + + OLAP Конструктор + + + +
+

OLAP Конструктор

+
+ + +
+
+ +
+ +
+

Поля

+
+ +
Найдено: {{ filteredAvailableFields.length }} / {{ availableFields.length }}
+
+ +
+ + + + +

Загрузка полей...

+
+
+ {{ error }} +
+
+ Нет доступных полей. Возможно, требуется инициализация структуры. +
+
+ +
+
+

Числовые → VALUES

+
+ {{ filteredNumberFields.length }} + +
+
+
+
+ {{ field.name }} + {{ field.tags?.slice(0,2).join(', ') }} +
+
+
+ + +
+
+

Категории → ROW / COLUMN

+
+ {{ filteredCategoryFields.length }} + +
+
+
+
+ {{ field.name }} + {{ field.tags?.slice(0,2).join(', ') }} +
+
+
+ + +
+
+

Фильтры

+
+ {{ filteredFilterFields.length }} + +
+
+
+
+ {{ field.name }} + {{ field.tags?.slice(0,2).join(', ') }} +
+
+
+
+ +
+
ROW:{{ rowFields.length }}
+
COLUMN:{{ columnFields.length }}
+
VALUES:{{ valueFields.length }}
+ +
+
+ + +
+ +
+
+ Тип отчета: + +
+ + +
+ + +
+ + +
Должно начинаться с буквы
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+

Пользовательские фильтры

+
+
+ {{ f.name }} +
+ + + + +
+ +
+
Перетащите поле фильтра
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + +
+
ROW
+
+
+ {{ f.name }} + +
+ Перетащите категорию +
+
+
COLUMN
+
+
+ {{ f.name }} + +
+ Перетащите категорию +
+
{{ rf.name }}{{ cf.name }} +
VALUES
+
+
+ {{ f.name }} + + +
+ Перетащите число +
+
+
+
+ +
+
+

Скрипт для ClickHouse

+ +
+
+
{{ sqlScript }}
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+ + + +
+

Сброс всех настроек

+

Вы уверены? Все выбранные поля, фильтры настройки будут удалены.

+
+ + +
+
+
+
+
+
+
+ + + + + diff --git a/iiko-app.dev.xserver.su.nginx.conf b/iiko-app.dev.xserver.su.nginx.conf index b39397c..a04acf9 100644 --- a/iiko-app.dev.xserver.su.nginx.conf +++ b/iiko-app.dev.xserver.su.nginx.conf @@ -42,38 +42,6 @@ server { proxy_set_header X-Forwarded-Proto $scheme; } - location /phpmyadmin/ { - allow 80.68.9.83; - allow 185.51.125.202; - - # Локальные сети - allow 192.168.0.0/16; # 192.168.0.0 - 192.168.255.255 - allow 10.0.0.0/8; # 10.0.0.0 - 10.255.255.255 - allow 172.16.0.0/12; # 172.16.0.0 - 172.31.255.255 - - allow fd00::/8; # IPv6 ULA (аналог приватных IPv4) - allow fe80::/10; # IPv6 link-local - - # Localhost - allow 127.0.0.0/8; # 127.0.0.0 - 127.255.255.255 - allow ::1; # IPv6 localhost - - # Docker сети (если используете) - allow 172.17.0.0/16; - allow 172.18.0.0/16; - - deny all; - - proxy_pass http://127.0.0.1:7102/; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection keep-alive; - proxy_set_header Host $host; - proxy_cache_bypass $http_upgrade; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - listen 443 ssl; ssl_certificate /etc/letsencrypt/live/iiko-app.dev.xserver.su/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/iiko-app.dev.xserver.su/privkey.pem; diff --git a/src/main/java/su/xserver/iikocon/iiko/IikoHandler.java b/src/main/java/su/xserver/iikocon/iiko/IikoHandler.java index 8037cc0..a9ec9fe 100644 --- a/src/main/java/su/xserver/iikocon/iiko/IikoHandler.java +++ b/src/main/java/su/xserver/iikocon/iiko/IikoHandler.java @@ -31,7 +31,7 @@ public class IikoHandler { log.error("Failed to initialize database", err); }); - router.route("/api/reports/olap/*").handler(authHandler::requireAuth); +// router.route("/api/reports/olap/*").handler(authHandler::requireAuth); router.get("/api/reports/olap/columns").handler(this::getColumns); router.delete("/api/reports/olap/columns/:fieldKey").handler(AdminHandler::requireAdmin).handler(this::deleteColumn); router.post("/api/reports/olap/initialize").handler(AdminHandler::requireAdmin).handler(this::postInitialize); diff --git a/src/main/java/su/xserver/iikocon/test/CodeGenerator.java b/src/main/java/su/xserver/iikocon/test/CodeGenerator.java new file mode 100644 index 0000000..902eaf9 --- /dev/null +++ b/src/main/java/su/xserver/iikocon/test/CodeGenerator.java @@ -0,0 +1,24 @@ +package su.xserver.iikocon.test; + +import java.security.SecureRandom; + +public class CodeGenerator { + + // SecureRandom — это криптостойкий генератор случайных чисел. + // Он обеспечивает непредсказуемость, что критично для безопасности. + private static final SecureRandom SECURE_RANDOM = new SecureRandom(); + + /** + * Генерирует шестизначный код подтверждения, соответствующий корпоративным стандартам. + * + * @return Строка, содержащая ровно 6 цифр. Первая цифра никогда не будет '0'. + */ + public static String generateCorporateCode() { + // Генерируем число в диапазоне от 100 000 до 999 999. + // Это гарантирует, что наш код всегда будет шестизначным. + int code = SECURE_RANDOM.nextInt(900_000) + 100_000; + return String.valueOf(code); + } + + +} diff --git a/src/main/java/su/xserver/iikocon/test/DateRangeSetup.java b/src/main/java/su/xserver/iikocon/test/DateRangeSetup.java index a687f6d..287233b 100644 --- a/src/main/java/su/xserver/iikocon/test/DateRangeSetup.java +++ b/src/main/java/su/xserver/iikocon/test/DateRangeSetup.java @@ -17,5 +17,14 @@ public class DateRangeSetup { System.out.println("dateFrom=" + formattedDateFrom); System.out.println("dateTo=" + formattedDateTo); + + System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode()); + System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode()); + System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode()); + System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode()); + System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode()); + System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode()); + System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode()); + } } diff --git a/src/main/java/su/xserver/iikocon/test/TestMail.java b/src/main/java/su/xserver/iikocon/test/TestMail.java new file mode 100644 index 0000000..30a11d1 --- /dev/null +++ b/src/main/java/su/xserver/iikocon/test/TestMail.java @@ -0,0 +1,198 @@ +package su.xserver.iikocon.test; + +import io.vertx.core.Vertx; +import io.vertx.ext.mail.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TestMail { + private static final Logger log = LoggerFactory.getLogger(TestMail.class); + public static void main(String[] args) { + Vertx vertx = Vertx.vertx(); + + MailConfig config = new MailConfig() + .setHostname("mail.xserver.su") + .setPort(465) + .setSsl(true) + .setStarttls(StartTLSOptions.REQUIRED) + .setUsername("admin.app@xserver.su") + .setPassword("SOLTiLS64TiL"); + + MailClient mailClient = MailClient.create(vertx, config); + +// MailMessage message = new MailMessage() +// .setFrom("bodrycraft@yandex.ru") +// .setTo("danil.bodry@vk.com") +// .setSubject("Hello from Vert.x") +// .setText("This is a test email sent using Vert.x Mail Client!"); + +// String htmlBody = """ +// +// +//

Заголовок письма

+//

Это основная часть письма с форматированием.

+//

Вы можете использовать жирный текст, +// ссылки и другие элементы.

+// Баннер
+//

С уважением,
Ваша команда

+// +// +// """; +// MailAttachment regularAttachment = MailAttachment.create() +// .setData(Buffer.buffer("Это содержимое текстового файла.")) +// .setName("информация.txt") +// .setContentType("text/plain"); +// MailAttachment inlineImage = MailAttachment.create() +// .setData(Buffer.buffer()) // Здесь должны быть данные вашего изображения +// .setContentType("image/png") +// .setContentId("bannerImage"); // Этот ID и используется в теге +// MailMessage message = new MailMessage() +// .setFrom("bodrycraft@yandex.ru") +// .setTo("danil.bodry@vk.com") +// .setSubject("Красивое письмо от Vert.x") +// .setText("Это обычная текстовая версия письма.") +// .setHtml(htmlBody) +// .setAttachment(regularAttachment) +// .setInlineAttachment(inlineImage); + + // 2. Генерируем 6-значный код + String verificationCode = CodeGenerator.generateCorporateCode(); + String recipientEmail = "danil.bodry@xserver.su"; + String userName = "Дорогой пользователь"; // можно подставить имя + + // 3. HTML-шаблон письма + String htmlBody = buildHtmlEmail(verificationCode, userName); + + // 4. Текстовая версия (plain text) + String textBody = String.format(""" + %s, + + Ваш код подтверждения: %s + + Для завершения входа введите этот код на странице авторизации. + Код действителен в течение 10 минут. + + Если вы не запрашивали вход, просто проигнорируйте это письмо. + + С уважением, + Команда поддержки + """, userName, verificationCode); + + // 5. Формируем письмо + MailMessage message = new MailMessage() + .setFrom("gallery@xserver.su") + .setTo(recipientEmail) + .setSubject("Ваш код для входа") +// .setText(textBody) + .setHtml(htmlBody); + + + mailClient.sendMail(message) + .onSuccess(res -> log.info("Success!")) + .onFailure(err -> log.error("Error: {}", err.getMessage())); + + + } + + private static String buildHtmlEmail(String code, String userName) { + return "\n" + + "\n" + + "\n" + + " \n" + + " \n" + + " Код подтверждения\n" + + " \n" + + "\n" + + "\n" + + "
\n" + + "
\n" + + "

Вход в аккаунт

\n" + + "
\n" + + "
\n" + + "
Здравствуйте, " + userName + "!
\n" + + "
\n" + + " Мы получили запрос на вход в ваш аккаунт. Используйте код подтверждения ниже, чтобы завершить вход.\n" + + "
\n" + + "
\n" + + "
Ваш одноразовый код
\n" + + "
" + code + "
\n" + + "
Действителен 10 минут
\n" + + "
\n" + + "
\n" + + " Перейти на страницу входа\n" + + "
\n" + + "
\n" + + " Если вы не запрашивали вход, просто проигнорируйте это письмо. Никому не сообщайте код.\n" + + "
\n" + + "
\n" + + "
\n" + + " (c) 2025 Ваша компания | Помощь | Безопасность\n" + + "
\n" + + "
\n" + + "\n" + + ""; + } +}