up
This commit is contained in:
@@ -2,6 +2,7 @@ import { createRouter, createWebHistory } from 'vue-router'
|
|||||||
import Login from '../views/auth/Login.vue'
|
import Login from '../views/auth/Login.vue'
|
||||||
import Setup from '../views/auth/Setup.vue'
|
import Setup from '../views/auth/Setup.vue'
|
||||||
import Dashboard from '../views/Dashboard.vue'
|
import Dashboard from '../views/Dashboard.vue'
|
||||||
|
import NotFound from '../views/NotFound.vue'
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{ path: '/login', component: Login, meta: { title: 'Login' } },
|
{ path: '/login', component: Login, meta: { title: 'Login' } },
|
||||||
@@ -14,6 +15,12 @@ const routes = [
|
|||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
redirect: '/dashboard'
|
redirect: '/dashboard'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/:pathMatch(.*)*',
|
||||||
|
name: 'NotFound',
|
||||||
|
component: NotFound,
|
||||||
|
meta: { title: 'Page Not Found', requiresAuth: false }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
34
frontend/src/views/NotFound.vue
Normal file
34
frontend/src/views/NotFound.vue
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<template>
|
||||||
|
<div class="min-h-screen bg-gray-50 flex items-center justify-center px-4">
|
||||||
|
<div class="text-center max-w-md">
|
||||||
|
<div class="mb-8">
|
||||||
|
<div class="w-32 h-32 mx-auto bg-primary-100 rounded-full flex items-center justify-center">
|
||||||
|
<svg class="w-16 h-16 text-primary-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h1 class="text-6xl font-bold text-gray-900 mb-4">404</h1>
|
||||||
|
<p class="text-xl text-gray-600 mb-8">Oops! Page not found</p>
|
||||||
|
<p class="text-gray-500 mb-8">The page you are looking for might have been removed, had its name changed, or is temporarily unavailable.</p>
|
||||||
|
<div class="flex flex-col sm:flex-row gap-4 justify-center">
|
||||||
|
<router-link
|
||||||
|
to="/dashboard"
|
||||||
|
class="px-6 py-3 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors"
|
||||||
|
>
|
||||||
|
Go to Dashboard
|
||||||
|
</router-link>
|
||||||
|
<router-link
|
||||||
|
to="/login"
|
||||||
|
class="px-6 py-3 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
||||||
|
>
|
||||||
|
Sign In
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
// No additional logic needed
|
||||||
|
</script>
|
||||||
BIN
libs/jackson-annotations-2.18.6.jar
Normal file
BIN
libs/jackson-annotations-2.18.6.jar
Normal file
Binary file not shown.
BIN
libs/jackson-databind-2.18.6.jar
Normal file
BIN
libs/jackson-databind-2.18.6.jar
Normal file
Binary file not shown.
BIN
libs/vertx-web-sstore-redis-5.0.10.jar
Normal file
BIN
libs/vertx-web-sstore-redis-5.0.10.jar
Normal file
Binary file not shown.
@@ -31,6 +31,7 @@ public class MainVerticle extends AbstractVerticle {
|
|||||||
private AppConfig config;
|
private AppConfig config;
|
||||||
|
|
||||||
private UserService userService;
|
private UserService userService;
|
||||||
|
private RestaurantService restaurantService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Promise<Void> startPromise) {
|
public void start(Promise<Void> startPromise) {
|
||||||
@@ -55,6 +56,7 @@ public class MainVerticle extends AbstractVerticle {
|
|||||||
|
|
||||||
// Инициализация сервисов
|
// Инициализация сервисов
|
||||||
userService = new UserService(db.getPool());
|
userService = new UserService(db.getPool());
|
||||||
|
restaurantService = new RestaurantService(db.getPool());
|
||||||
|
|
||||||
// Инициализация БД (создание таблицы users)
|
// Инициализация БД (создание таблицы users)
|
||||||
userService.initDatabase()
|
userService.initDatabase()
|
||||||
@@ -64,6 +66,13 @@ public class MainVerticle extends AbstractVerticle {
|
|||||||
startPromise.fail(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);
|
||||||
|
});
|
||||||
|
|
||||||
Router router = initRouter();
|
Router router = initRouter();
|
||||||
|
|
||||||
startHttp(router, startPromise);
|
startHttp(router, startPromise);
|
||||||
@@ -127,22 +136,16 @@ public class MainVerticle extends AbstractVerticle {
|
|||||||
AuthHandler authHandler = new AuthHandler(userService);
|
AuthHandler authHandler = new AuthHandler(userService);
|
||||||
SetupHandler setupHandler = new SetupHandler(userService);
|
SetupHandler setupHandler = new SetupHandler(userService);
|
||||||
|
|
||||||
// Проверка статуса (нужна ли инициализация)
|
|
||||||
router.get("/api/status").handler(setupHandler::checkStatus);
|
router.get("/api/status").handler(setupHandler::checkStatus);
|
||||||
|
|
||||||
// Регистрация первого администратора
|
|
||||||
router.post("/api/setup").handler(setupHandler::handleSetup);
|
router.post("/api/setup").handler(setupHandler::handleSetup);
|
||||||
|
|
||||||
// Логин
|
|
||||||
router.post("/api/login").handler(authHandler::handleLogin);
|
router.post("/api/login").handler(authHandler::handleLogin);
|
||||||
|
|
||||||
// Выход
|
|
||||||
router.post("/api/logout").handler(authHandler::handleLogout);
|
router.post("/api/logout").handler(authHandler::handleLogout);
|
||||||
|
|
||||||
// Защищённые маршруты
|
|
||||||
router.route("/api/admin/*").handler(authHandler::requireAuth);
|
router.route("/api/admin/*").handler(authHandler::requireAuth);
|
||||||
|
|
||||||
// Получение списка пользователей
|
|
||||||
router.get("/api/admin/users").handler(rc -> userService.getAllUsers().onComplete(ar -> {
|
router.get("/api/admin/users").handler(rc -> userService.getAllUsers().onComplete(ar -> {
|
||||||
if (ar.succeeded()) {
|
if (ar.succeeded()) {
|
||||||
rc.response()
|
rc.response()
|
||||||
@@ -168,11 +171,6 @@ public class MainVerticle extends AbstractVerticle {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Статическая раздача фронтенда
|
|
||||||
// router.route("/*").handler(StaticHandler.create("webroot")
|
|
||||||
// .setCachingEnabled(false)
|
|
||||||
// .setIndexPage("index.html"));
|
|
||||||
|
|
||||||
return router;
|
return router;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
93
src/main/java/su/xserver/iikocon/RestaurantService.java
Normal file
93
src/main/java/su/xserver/iikocon/RestaurantService.java
Normal file
@@ -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<Void> 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<Long> countRestaurant() {
|
||||||
|
return pool.query("SELECT COUNT(*) AS cnt FROM restaurants")
|
||||||
|
.execute()
|
||||||
|
.map(rows -> rows.iterator().next().getLong("cnt"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Future<Void> createRestaurant(String name, String login, String password, String host) {
|
||||||
|
|
||||||
|
Map<String, Object> 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<JsonObject> 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<JsonArray> 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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user