diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index e3ccf49..04278eb 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -2,6 +2,7 @@ import { createRouter, createWebHistory } from 'vue-router' import Login from '../views/auth/Login.vue' import Setup from '../views/auth/Setup.vue' import Dashboard from '../views/Dashboard.vue' +import NotFound from '../views/NotFound.vue' const routes = [ { path: '/login', component: Login, meta: { title: 'Login' } }, @@ -14,6 +15,12 @@ const routes = [ { path: '/', redirect: '/dashboard' + }, + { + path: '/:pathMatch(.*)*', + name: 'NotFound', + component: NotFound, + meta: { title: 'Page Not Found', requiresAuth: false } } ] diff --git a/frontend/src/views/NotFound.vue b/frontend/src/views/NotFound.vue new file mode 100644 index 0000000..0982d18 --- /dev/null +++ b/frontend/src/views/NotFound.vue @@ -0,0 +1,34 @@ + + + + + + + + + + + 404 + Oops! Page not found + The page you are looking for might have been removed, had its name changed, or is temporarily unavailable. + + + Go to Dashboard + + + Sign In + + + + + + + diff --git a/libs/jackson-annotations-2.18.6.jar b/libs/jackson-annotations-2.18.6.jar new file mode 100644 index 0000000..2bd7a58 Binary files /dev/null and b/libs/jackson-annotations-2.18.6.jar differ diff --git a/libs/jackson-databind-2.18.6.jar b/libs/jackson-databind-2.18.6.jar new file mode 100644 index 0000000..f776af7 Binary files /dev/null and b/libs/jackson-databind-2.18.6.jar differ diff --git a/libs/vertx-web-sstore-redis-5.0.10.jar b/libs/vertx-web-sstore-redis-5.0.10.jar new file mode 100644 index 0000000..ddcb818 Binary files /dev/null and b/libs/vertx-web-sstore-redis-5.0.10.jar differ diff --git a/src/main/java/su/xserver/iikocon/MainVerticle.java b/src/main/java/su/xserver/iikocon/MainVerticle.java index b15276d..91ab754 100644 --- a/src/main/java/su/xserver/iikocon/MainVerticle.java +++ b/src/main/java/su/xserver/iikocon/MainVerticle.java @@ -31,6 +31,7 @@ public class MainVerticle extends AbstractVerticle { private AppConfig config; private UserService userService; + private RestaurantService restaurantService; @Override public void start(Promise startPromise) { @@ -55,6 +56,7 @@ public class MainVerticle extends AbstractVerticle { // Инициализация сервисов userService = new UserService(db.getPool()); + restaurantService = new RestaurantService(db.getPool()); // Инициализация БД (создание таблицы users) userService.initDatabase() @@ -64,6 +66,13 @@ public class MainVerticle extends AbstractVerticle { startPromise.fail(err); }); + restaurantService.initDatabase() + .onSuccess(v -> log.info("Database initialized successfully")) + .onFailure(err -> { + log.error("Failed to initialize database", err); + startPromise.fail(err); + }); + Router router = initRouter(); startHttp(router, startPromise); @@ -127,22 +136,16 @@ public class MainVerticle extends AbstractVerticle { AuthHandler authHandler = new AuthHandler(userService); SetupHandler setupHandler = new SetupHandler(userService); - // Проверка статуса (нужна ли инициализация) router.get("/api/status").handler(setupHandler::checkStatus); - // Регистрация первого администратора router.post("/api/setup").handler(setupHandler::handleSetup); - // Логин router.post("/api/login").handler(authHandler::handleLogin); - // Выход router.post("/api/logout").handler(authHandler::handleLogout); - // Защищённые маршруты router.route("/api/admin/*").handler(authHandler::requireAuth); - // Получение списка пользователей router.get("/api/admin/users").handler(rc -> userService.getAllUsers().onComplete(ar -> { if (ar.succeeded()) { rc.response() @@ -168,11 +171,6 @@ public class MainVerticle extends AbstractVerticle { } }); - // Статическая раздача фронтенда -// router.route("/*").handler(StaticHandler.create("webroot") -// .setCachingEnabled(false) -// .setIndexPage("index.html")); - return router; } diff --git a/src/main/java/su/xserver/iikocon/RestaurantService.java b/src/main/java/su/xserver/iikocon/RestaurantService.java new file mode 100644 index 0000000..a084a49 --- /dev/null +++ b/src/main/java/su/xserver/iikocon/RestaurantService.java @@ -0,0 +1,93 @@ +package su.xserver.iikocon; + +import io.vertx.core.Future; +import io.vertx.core.json.JsonArray; +import io.vertx.core.json.JsonObject; +import io.vertx.sqlclient.Pool; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.templates.SqlTemplate; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class RestaurantService { + private final Pool pool; + + public RestaurantService(Pool pool) { + this.pool = pool; + } + + public Future initDatabase() { + String createTable = """ + CREATE TABLE IF NOT EXISTS restaurants ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) UNIQUE NOT NULL, + login VARCHAR(255) UNIQUE NOT NULL, + password VARCHAR(255) NOT NULL, + host VARCHAR(255) NOT NULL, + created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP + ) + """; + + return pool.query(createTable).execute().mapEmpty(); + } + + public Future countRestaurant() { + return pool.query("SELECT COUNT(*) AS cnt FROM restaurants") + .execute() + .map(rows -> rows.iterator().next().getLong("cnt")); + } + + public Future createRestaurant(String name, String login, String password, String host) { + + Map params = new HashMap<>(); + params.put("name", name); + params.put("login", login); + params.put("password", password); + params.put("host", host); + + return SqlTemplate.forUpdate(pool, + "INSERT INTO restaurants (name, login, password, host) VALUES (#{name}, #{login}, #{password}, #{host})") + .execute(params) + .mapEmpty(); + } + + public Future findByName(String name) { + return SqlTemplate.forQuery(pool, + "SELECT id, name, login, password, created, updated, host FROM restaurants WHERE name = #{name}") + .mapTo(row -> new JsonObject() + .put("id", row.getInteger("id")) + .put("name", row.getString("name")) + .put("login", row.getString("login")) + .put("password", row.getString("password")) + .put("created", row.getLocalDateTime("created") != null ? + row.getLocalDateTime("created").toString() : null) + .put("updated", row.getLocalDateTime("updated") != null ? + row.getLocalDateTime("updated").toString() : null) + .put("host", row.getString("host"))) + .execute(Collections.singletonMap("name", name)) + .map(rows -> rows.iterator().hasNext() ? rows.iterator().next() : null); + } + + public Future getAllRestaurants() { + return pool.query("SELECT id, name, login, created, updated, host FROM restaurants 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("name", row.getString("name")) + .put("created", row.getLocalDateTime("created") != null ? + row.getLocalDateTime("created").toString() : null) + .put("updated", row.getLocalDateTime("updated") != null ? + row.getLocalDateTime("updated").toString() : null) + .put("host", row.getString("host"))); + } + return array; + }); + } +}
Oops! Page not found
The page you are looking for might have been removed, had its name changed, or is temporarily unavailable.