From 206815465607982f605c4459efba8475cc92e23d Mon Sep 17 00:00:00 2001 From: Danil-Bodry Date: Sat, 18 Apr 2026 12:20:44 +0300 Subject: [PATCH] up --- frontend/src/router/index.ts | 14 ++- frontend/src/views/AdminSettings.vue | 37 ++++++++ frontend/src/views/Dashboard.vue | 31 +++++- frontend/src/views/Users.vue | 31 ++++-- frontend/src/views/auth/Login.vue | 4 +- frontend/src/views/auth/Register.vue | 72 ++++++++++++++ frontend/src/views/auth/Setup.vue | 59 ++++++++---- .../java/su/xserver/iikocon/MainVerticle.java | 95 +++++++++++++++---- .../su/xserver/iikocon/RestaurantService.java | 2 +- .../su/xserver/iikocon/SettingsService.java | 67 +++++++++++++ .../java/su/xserver/iikocon/SetupHandler.java | 7 +- .../java/su/xserver/iikocon/UserService.java | 92 ++++++++++-------- .../iikocon/service/HealthCheckService.java | 4 +- 13 files changed, 423 insertions(+), 92 deletions(-) create mode 100644 frontend/src/views/AdminSettings.vue create mode 100644 frontend/src/views/auth/Register.vue create mode 100644 src/main/java/su/xserver/iikocon/SettingsService.java diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index 279a411..ad4b558 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -1,14 +1,17 @@ import { createRouter, createWebHistory } from 'vue-router' import Login from '../views/auth/Login.vue' import Setup from '../views/auth/Setup.vue' +import Register from '../views/auth/Register.vue' import Dashboard from '../views/Dashboard.vue' import Users from '../views/Users.vue' import Restaurants from '../views/Restaurants.vue' +import AdminSettings from '../views/AdminSettings.vue' import NotFound from '../views/NotFound.vue' const routes = [ { path: '/login', component: Login, meta: { title: 'Login' } }, { path: '/setup', component: Setup, meta: { title: 'Setup' } }, + { path: '/register', component: Register, meta: { title: 'Register' } }, { path: '/', redirect: '/dashboard' @@ -18,14 +21,21 @@ const routes = [ component: Dashboard, meta: { requiresAuth: true, title: 'Dashboard' } }, - { path: '/users', + { + path: '/users', component: Users, meta: { requiresAuth: true, title: 'Users' } }, - { path: '/restaurants', + { + path: '/restaurants', component: Restaurants, meta: { requiresAuth: true, title: 'Restaurants' } }, + { + path: '/settings', + component: AdminSettings, + meta: { requiresAuth: true, title: 'Settings' } + }, { path: '/:pathMatch(.*)*', name: 'NotFound', diff --git a/frontend/src/views/AdminSettings.vue b/frontend/src/views/AdminSettings.vue new file mode 100644 index 0000000..1f065e8 --- /dev/null +++ b/frontend/src/views/AdminSettings.vue @@ -0,0 +1,37 @@ + + + diff --git a/frontend/src/views/Dashboard.vue b/frontend/src/views/Dashboard.vue index 38efb93..398179a 100644 --- a/frontend/src/views/Dashboard.vue +++ b/frontend/src/views/Dashboard.vue @@ -118,11 +118,32 @@ import { ref, onMounted, onUnmounted } from 'vue' import AppLayout from '../components/Layout/AppLayout.vue' -const stats = ref({ - totalUsers: 0, - activeSessions: 0, - systemHealth: 98, - uptime: '99.9%' +const stats = ref({ totalUsers: 0, activeSessions: 0, systemHealth: 100, uptime: '99.9%' }) + +async function loadStats() { + try { + const [usersRes, sessionsRes, healthRes] = await Promise.all([ + fetch('/api/admin/users'), + fetch('/api/admin/active-sessions'), + fetch('/api/health') + ]) + const users = await usersRes.json() + const sessions = await sessionsRes.json() + const health = await healthRes.json() + + stats.value.totalUsers = users.length + stats.value.activeSessions = sessions.count || 0 + + const upCount = health.checks?.filter(c => c.status === 'UP').length || 0 + const total = health.checks?.length || 1 + stats.value.systemHealth = Math.round((upCount / total) * 100) + } catch (e) { console.error(e) } +} + +onMounted(() => { + loadStats() + const interval = setInterval(loadStats, 5000) + onUnmounted(() => clearInterval(interval)) }) const recentUsers = ref([]) diff --git a/frontend/src/views/Users.vue b/frontend/src/views/Users.vue index 98f2236..df3d728 100644 --- a/frontend/src/views/Users.vue +++ b/frontend/src/views/Users.vue @@ -11,20 +11,28 @@ ID Login + Email + Active IP Created Actions - + - {{ user.id }} - {{ user.login }} - {{ user.ip || '-' }} - {{ formatDate(user.created) }} + {{ user.id }} + {{ user.login }} + {{ user.email }} + + + + {{ user.ip || '-' }} + {{ formatDate(user.created) }} - - + + @@ -36,6 +44,10 @@

{{ modalTitle }}

+
+ + +
@@ -75,6 +87,11 @@ function formatDate(dateStr: string) { return new Date(dateStr).toLocaleString(); } +async function toggleActive(user: any) { + await fetch(`/api/admin/users/${user.id}/activate?active=${!user.active}`, { method: 'PUT' }) + await loadUsers() +} + function openModal(mode: 'create' | 'edit', user: any = null) { modalMode.value = mode; if (mode === 'create') { diff --git a/frontend/src/views/auth/Login.vue b/frontend/src/views/auth/Login.vue index 0006f69..bb40360 100644 --- a/frontend/src/views/auth/Login.vue +++ b/frontend/src/views/auth/Login.vue @@ -67,7 +67,9 @@ Remember me - Forgot password? + + Create account +
+
+

Account created! Wait for admin activation.

+

{{ error }}

+

+ Already have an account? Login +

+
+ + + + + diff --git a/frontend/src/views/auth/Setup.vue b/frontend/src/views/auth/Setup.vue index 5f5b29d..5915cd4 100644 --- a/frontend/src/views/auth/Setup.vue +++ b/frontend/src/views/auth/Setup.vue @@ -51,6 +51,26 @@

{{ validation.login }}

+
+ +
+
+ + + +
+ +
+

{{ validation.email }}

+
+
@@ -133,21 +153,24 @@ import { ref, computed, watch } from 'vue' import { useRouter } from 'vue-router' const router = useRouter() -const form = ref({ login: '', password: '' }) +const form = ref({ login: '', email: '', password: '' }); const loading = ref(false) const error = ref('') const showPassword = ref(false) const validation = computed(() => { - const errors: any = {} + const errors: any = {}; if (form.value.login && form.value.login.length < 3) { - errors.login = 'Username must be at least 3 characters' + errors.login = 'Username must be at least 3 characters'; + } + if (form.value.email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(form.value.email)) { + errors.email = 'Please enter a valid email address'; } if (form.value.password && form.value.password.length < 6) { - errors.password = 'Password must be at least 6 characters' + errors.password = 'Password must be at least 6 characters'; } - return errors -}) + return errors; +}); const passwordStrength = computed(() => { const pwd = form.value.password @@ -178,29 +201,33 @@ const strengthBarColor = computed(() => { }) async function handleSetup() { - if (Object.keys(validation.value).length > 0) return + if (Object.keys(validation.value).length > 0) return; - loading.value = true - error.value = '' + loading.value = true; + error.value = ''; try { const res = await fetch('/api/setup', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(form.value) - }) + body: JSON.stringify({ + login: form.value.login, + email: form.value.email, + password: form.value.password + }) + }); - const data = await res.json() + const data = await res.json(); if (res.ok) { - router.push('/login') + router.push('/login'); } else { - error.value = data.error || 'Failed to create account' + error.value = data.error || 'Failed to create account'; } } catch (e) { - error.value = 'Network error. Please try again.' + error.value = 'Network error. Please try again.'; } finally { - loading.value = false + loading.value = false; } } diff --git a/src/main/java/su/xserver/iikocon/MainVerticle.java b/src/main/java/su/xserver/iikocon/MainVerticle.java index d4ee32f..82d731c 100644 --- a/src/main/java/su/xserver/iikocon/MainVerticle.java +++ b/src/main/java/su/xserver/iikocon/MainVerticle.java @@ -4,6 +4,7 @@ import io.vertx.config.ConfigRetriever; import io.vertx.config.ConfigRetrieverOptions; import io.vertx.config.ConfigStoreOptions; import io.vertx.core.AbstractVerticle; +import io.vertx.core.Future; import io.vertx.core.Promise; import io.vertx.core.http.HttpServer; import io.vertx.core.json.JsonObject; @@ -14,6 +15,7 @@ import io.vertx.ext.web.handler.StaticHandler; import io.vertx.ext.web.sstore.LocalSessionStore; import io.vertx.ext.web.sstore.SessionStore; +import io.vertx.ext.web.sstore.redis.RedisSessionStore; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import su.xserver.iikocon.config.AppConfig; @@ -21,6 +23,10 @@ import su.xserver.iikocon.service.DataBaseService; import su.xserver.iikocon.service.HealthCheckService; import su.xserver.iikocon.service.RedisService; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; + public class MainVerticle extends AbstractVerticle { private final Logger log = LoggerFactory.getLogger("[MainVerticle]"); @@ -32,6 +38,7 @@ public class MainVerticle extends AbstractVerticle { private UserService userService; private RestaurantService restaurantService; + private SettingsService settingsService; @Override public void start(Promise startPromise) { @@ -57,21 +64,21 @@ public class MainVerticle extends AbstractVerticle { // Инициализация сервисов userService = new UserService(db.getPool()); restaurantService = new RestaurantService(db.getPool()); + settingsService = new SettingsService(db.getPool()); // Инициализация БД (создание таблицы users) - userService.initDatabase() - .onSuccess(v -> log.info("Database initialized successfully")) - .onFailure(err -> { - log.error("Failed to initialize database", err); - startPromise.fail(err); - }); - - restaurantService.initDatabase() - .onSuccess(v -> log.info("Database initialized successfully")) - .onFailure(err -> { - log.error("Failed to initialize database", err); - startPromise.fail(err); - }); + userService.initDatabase().onFailure(err -> { + log.error("Failed to initialize database", err); + startPromise.fail(err); + }); + restaurantService.initDatabase().onFailure(err -> { + log.error("Failed to initialize database", err); + startPromise.fail(err); + }); + settingsService.initDatabase().onFailure(err -> { + log.error("Failed to initialize database", err); + startPromise.fail(err); + }); Router router = initRouter(); @@ -90,7 +97,7 @@ public class MainVerticle extends AbstractVerticle { .setSessionCookieName("admin.session") .setCookieHttpOnlyFlag(true) .setCookieSecureFlag(false) - .setSessionTimeout(3600000); // 1 час + .setSessionTimeout(3600000); // Роутер Router router = Router.router(vertx); @@ -144,6 +151,21 @@ public class MainVerticle extends AbstractVerticle { router.post("/api/logout").handler(authHandler::handleLogout); + router.post("/api/register").handler(rc -> { + JsonObject body = rc.body().asJsonObject(); + String login = body.getString("login"); + String email = body.getString("email"); + String password = body.getString("password"); + String ip = rc.request().remoteAddress().host(); + if (login == null || email == null || password == null) { + rc.response().setStatusCode(400).end("Missing fields"); + return; + } + userService.createUser(login, email, password, ip) + .onSuccess(v -> rc.response().setStatusCode(201).end(new JsonObject().put("success", true).encode())) + .onFailure(err -> rc.response().setStatusCode(500).end(err.getMessage())); + }); + router.route("/api/admin/*").handler(authHandler::requireAuth); router.get("/api/admin/users").handler(rc -> userService.getAllUsers().onComplete(ar -> { @@ -159,13 +181,14 @@ public class MainVerticle extends AbstractVerticle { router.post("/api/admin/users").handler(rc -> { JsonObject body = rc.body().asJsonObject(); String login = body.getString("login"); + String email = body.getString("email"); String password = body.getString("password"); String ip = rc.request().remoteAddress().host(); - if (login == null || password == null) { - rc.response().setStatusCode(400).end("Missing login or password"); + if (login == null || email == null || password == null) { + rc.response().setStatusCode(400).end("Missing login, email or password"); return; } - userService.createUser(login, password, ip) + userService.createUser(login, email, password, ip, true) .onSuccess(v -> rc.response().setStatusCode(201).end()) .onFailure(err -> rc.response().setStatusCode(500).end(err.getMessage())); }); @@ -174,13 +197,14 @@ public class MainVerticle extends AbstractVerticle { int id = Integer.parseInt(rc.pathParam("id")); JsonObject body = rc.body().asJsonObject(); String login = body.getString("login"); + String email = body.getString("email"); String password = body.getString("password"); String ip = rc.request().remoteAddress().host(); - if (login == null) { - rc.response().setStatusCode(400).end("Missing login"); + if (login == null || email == null) { + rc.response().setStatusCode(400).end("Missing login or email"); return; } - userService.updateUser(id, login, password, ip) + userService.updateUser(id, login, email, password, ip) .onSuccess(v -> rc.response().end()) .onFailure(err -> rc.response().setStatusCode(500).end(err.getMessage())); }); @@ -192,6 +216,14 @@ public class MainVerticle extends AbstractVerticle { .onFailure(err -> rc.response().setStatusCode(500).end(err.getMessage())); }); + router.put("/api/admin/users/:id/activate").handler(rc -> { + int id = Integer.parseInt(rc.pathParam("id")); + boolean active = Boolean.parseBoolean(rc.queryParam("active").get(0)); + userService.setActive(id, active) + .onSuccess(v -> rc.response().end()) + .onFailure(err -> rc.response().setStatusCode(500).end(err.getMessage())); + }); + // Получение текущего пользователя router.get("/api/admin/me").handler(rc -> { Integer userId = rc.session().get("userId"); @@ -265,6 +297,29 @@ public class MainVerticle extends AbstractVerticle { .onFailure(err -> rc.response().setStatusCode(500).end(err.getMessage())); }); + // Получение всех настроек + router.get("/api/settings").handler(rc -> { + settingsService.getAll() + .onSuccess(settings -> rc.response().putHeader("Content-Type", "application/json").end(settings.encode())) + .onFailure(err -> rc.response().setStatusCode(500).end(err.getMessage())); + }); + +// Обновление настроек (админ) + router.put("/api/admin/settings").handler(rc -> { + JsonObject body = rc.body().asJsonObject(); + List> futures = new ArrayList<>(); // явно указываем тип Future + body.forEach(entry -> futures.add(settingsService.set(entry.getKey(), entry.getValue().toString()))); + Future.all(futures) + .onSuccess(v -> rc.response().end()) + .onFailure(err -> rc.response().setStatusCode(500).end(err.getMessage())); + }); + +// Количество активных сессий (на основе Redis) + router.get("/api/admin/active-sessions").handler(rc -> { + // TODO: реализовать подсчёт активных сессий через Redis или другой механизм + rc.response().end(new JsonObject().put("count", 0).encode()); + }); + return router; } diff --git a/src/main/java/su/xserver/iikocon/RestaurantService.java b/src/main/java/su/xserver/iikocon/RestaurantService.java index 72c975b..63b031e 100644 --- a/src/main/java/su/xserver/iikocon/RestaurantService.java +++ b/src/main/java/su/xserver/iikocon/RestaurantService.java @@ -23,7 +23,7 @@ public class RestaurantService { CREATE TABLE IF NOT EXISTS restaurants ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) UNIQUE NOT NULL, - login VARCHAR(255) UNIQUE NOT NULL, + login VARCHAR(255) NOT NULL, password VARCHAR(255) NOT NULL, host VARCHAR(255) NOT NULL, created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, diff --git a/src/main/java/su/xserver/iikocon/SettingsService.java b/src/main/java/su/xserver/iikocon/SettingsService.java new file mode 100644 index 0000000..d48c3b2 --- /dev/null +++ b/src/main/java/su/xserver/iikocon/SettingsService.java @@ -0,0 +1,67 @@ +package su.xserver.iikocon; + +import io.vertx.core.Future; +import io.vertx.core.json.JsonObject; +import io.vertx.sqlclient.Pool; +import io.vertx.sqlclient.templates.SqlTemplate; + +import java.util.Map; + +public class SettingsService { + private final Pool pool; + + public SettingsService(Pool pool) { this.pool = pool; } + + public Future initDatabase() { + String createTable = """ + CREATE TABLE IF NOT EXISTS app_settings ( + setting_key VARCHAR(255) PRIMARY KEY, + setting_value TEXT + ) + """; + return pool.query(createTable).execute() + .compose(v -> setIfAbsent("site_name", "Admin Panel")) + .compose(v -> setIfAbsent("site_description", "Powerful administration dashboard")) + .compose(v -> setIfAbsent("theme", "light")) + .compose(v -> setIfAbsent("items_per_page", "20")) + .compose(v -> setIfAbsent("enable_registration", "true")) + .compose(v -> setIfAbsent("maintenance_mode", "false")) + .compose(v -> setIfAbsent("default_language", "en")) + .compose(v -> setIfAbsent("session_timeout_minutes", "60")) + .compose(v -> setIfAbsent("logo_url", "/assets/logo.png")) + .mapEmpty(); + } + + private Future setIfAbsent(String key, String defaultValue) { + return get(key).compose(existing -> { + if (existing == null) { + return set(key, defaultValue); + } + return Future.succeededFuture(); + }); + } + + public Future get(String key) { + return SqlTemplate.forQuery(pool, "SELECT setting_value FROM app_settings WHERE setting_key = #{key}") + .execute(Map.of("key", key)) + .map(rows -> rows.iterator().hasNext() ? rows.iterator().next().getString("setting_value") : null); + } + + public Future set(String key, String value) { + return SqlTemplate.forUpdate(pool, + "INSERT INTO app_settings (setting_key, setting_value) VALUES (#{key}, #{value}) " + + "ON DUPLICATE KEY UPDATE setting_value = #{value}") + .execute(Map.of("key", key, "value", value)) + .mapEmpty(); + } + + public Future getAll() { + return pool.query("SELECT setting_key, setting_value FROM app_settings") + .execute() + .map(rows -> { + JsonObject json = new JsonObject(); + rows.forEach(row -> json.put(row.getString("setting_key"), row.getString("setting_value"))); + return json; + }); + } +} diff --git a/src/main/java/su/xserver/iikocon/SetupHandler.java b/src/main/java/su/xserver/iikocon/SetupHandler.java index 8e2209a..f7c3826 100644 --- a/src/main/java/su/xserver/iikocon/SetupHandler.java +++ b/src/main/java/su/xserver/iikocon/SetupHandler.java @@ -37,6 +37,11 @@ public class SetupHandler { String login = body.getString("login"); String password = body.getString("password"); + String email = body.getString("email"); + + if (email == null || email.isBlank()) { + email = login + "@admin.local"; // значение по умолчанию + } if (login == null || password == null || login.length() < 3 || password.length() < 6) { ctx.response().setStatusCode(400) @@ -47,7 +52,7 @@ public class SetupHandler { } String ip = ctx.request().remoteAddress().host(); - userService.createUser(login, password, ip).onComplete(cr -> { + userService.createUser(login, email, password, ip, true).onComplete(cr -> { if (cr.succeeded()) { ctx.response().setStatusCode(201) .end(new JsonObject().put("success", true).encode()); diff --git a/src/main/java/su/xserver/iikocon/UserService.java b/src/main/java/su/xserver/iikocon/UserService.java index fcb7535..1e41a86 100644 --- a/src/main/java/su/xserver/iikocon/UserService.java +++ b/src/main/java/su/xserver/iikocon/UserService.java @@ -21,16 +21,17 @@ public class UserService { public Future initDatabase() { String createTable = """ - CREATE TABLE IF NOT EXISTS users ( - id INT AUTO_INCREMENT PRIMARY KEY, - login VARCHAR(255) UNIQUE NOT NULL, - password VARCHAR(255) NOT NULL, - created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - ip VARCHAR(45) - ) - """; - + CREATE TABLE IF NOT EXISTS users ( + id INT AUTO_INCREMENT PRIMARY KEY, + login VARCHAR(255) UNIQUE NOT NULL, + email VARCHAR(255) UNIQUE NOT NULL, + password VARCHAR(255) NOT NULL, + active BOOLEAN DEFAULT FALSE, + ip VARCHAR(45), + created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP + ) + """; return pool.query(createTable).execute().mapEmpty(); } @@ -40,20 +41,38 @@ public class UserService { .map(rows -> rows.iterator().next().getLong("cnt")); } - public Future createUser(String login, String password, String ip) { + public Future createUser(String login, String email, String password, String ip, boolean active) { String hash = BCrypt.hashpw(password, BCrypt.gensalt()); - - Map params = new HashMap<>(); - params.put("login", login); - params.put("password", hash); - params.put("ip", ip); - + Map params = Map.of( + "login", login, + "email", email, + "password", hash, + "ip", ip, + "active", active + ); return SqlTemplate.forUpdate(pool, - "INSERT INTO users (login, password, ip) VALUES (#{login}, #{password}, #{ip})") + "INSERT INTO users (login, email, password, ip, active) VALUES (#{login}, #{email}, #{password}, #{ip}, #{active})") .execute(params) .mapEmpty(); } + // Существующий метод оставляем, но он будет создавать неактивного пользователя (active = false) + public Future createUser(String login, String email, String password, String ip) { + return createUser(login, email, password, ip, false); + } + + public Future setActive(int id, boolean active) { + return SqlTemplate.forUpdate(pool, "UPDATE users SET active = #{active} WHERE id = #{id}") + .execute(Map.of("id", id, "active", active)).mapEmpty(); + } + + public Future findByEmail(String email) { + return SqlTemplate.forQuery(pool, "SELECT id, login, email, password, active, ip, created, updated FROM users WHERE email = #{email}") + .mapTo(this::toJson) + .execute(Map.of("email", email)) + .map(rows -> rows.iterator().hasNext() ? rows.iterator().next() : null); + } + public Future findByLogin(String login) { return SqlTemplate.forQuery(pool, "SELECT id, login, password, created, updated, ip FROM users WHERE login = #{login}") @@ -71,42 +90,30 @@ public class UserService { } public Future getAllUsers() { - return pool.query("SELECT id, login, created, updated, ip FROM users ORDER BY id") + return pool.query("SELECT id, login, email, active, ip, created, updated FROM users ORDER BY id") .execute() .map(rows -> { JsonArray array = new JsonArray(); - for (Row row : rows) { - array.add(new JsonObject() - .put("id", row.getInteger("id")) - .put("login", row.getString("login")) - .put("created", row.getLocalDateTime("created") != null ? - row.getLocalDateTime("created").toString() : null) - .put("updated", row.getLocalDateTime("updated") != null ? - row.getLocalDateTime("updated").toString() : null) - .put("ip", row.getString("ip"))); - } + rows.forEach(row -> array.add(toJson(row))); return array; }); } - public Future updateUser(int id, String login, String password, String ip) { + public Future updateUser(int id, String login, String email, String password, String ip) { Map params = new HashMap<>(); params.put("id", id); params.put("login", login); + params.put("email", email); params.put("ip", ip); - String sql; if (password != null && !password.isEmpty()) { String hash = BCrypt.hashpw(password, BCrypt.gensalt()); params.put("password", hash); - sql = "UPDATE users SET login = #{login}, password = #{password}, ip = #{ip} WHERE id = #{id}"; + sql = "UPDATE users SET login = #{login}, email = #{email}, password = #{password}, ip = #{ip} WHERE id = #{id}"; } else { - sql = "UPDATE users SET login = #{login}, ip = #{ip} WHERE id = #{id}"; + sql = "UPDATE users SET login = #{login}, email = #{email}, ip = #{ip} WHERE id = #{id}"; } - - return SqlTemplate.forUpdate(pool, sql) - .execute(params) - .mapEmpty(); + return SqlTemplate.forUpdate(pool, sql).execute(params).mapEmpty(); } public Future deleteUser(int id) { @@ -122,4 +129,15 @@ public class UserService { return false; } } + + private JsonObject toJson(Row row) { + return new JsonObject() + .put("id", row.getInteger("id")) + .put("login", row.getString("login")) + .put("email", row.getString("email")) + .put("active", row.getBoolean("active")) + .put("ip", row.getString("ip")) + .put("created", row.getLocalDateTime("created") != null ? row.getLocalDateTime("created").toString() : null) + .put("updated", row.getLocalDateTime("updated") != null ? row.getLocalDateTime("updated").toString() : null); + } } diff --git a/src/main/java/su/xserver/iikocon/service/HealthCheckService.java b/src/main/java/su/xserver/iikocon/service/HealthCheckService.java index 99b0afc..66abc35 100644 --- a/src/main/java/su/xserver/iikocon/service/HealthCheckService.java +++ b/src/main/java/su/xserver/iikocon/service/HealthCheckService.java @@ -31,7 +31,7 @@ public class HealthCheckService { long time = System.currentTimeMillis() - start; if ("PONG".equalsIgnoreCase(response.toString())) { JsonObject data = new JsonObject() - .put("name", "redis") + .put("name", "Redis") .put("latency_ms", time); future.complete(Status.OK(data)); } else { @@ -42,7 +42,7 @@ public class HealthCheckService { }); // Database check - healthCheckHandler.register("database", future -> { + healthCheckHandler.register("DataBase", future -> { long start = System.currentTimeMillis(); dbService.getPool().query("SELECT 1").execute() .onSuccess(rs -> {