diff --git a/middleware/firstRun.ts b/middleware/firstRun.ts new file mode 100644 index 0000000..9bb58b4 --- /dev/null +++ b/middleware/firstRun.ts @@ -0,0 +1,8 @@ +import { defineNuxtRouteMiddleware, navigateTo, useFetch } from "nuxt/app"; + +export default defineNuxtRouteMiddleware(async (to, from) => { + const firstRun = await useFetch("/api/firstRun"); + + if (firstRun.data.value) + return navigateTo({ path: "/firstRun" }); +}); diff --git a/pages/firstRun.vue b/pages/firstRun.vue new file mode 100644 index 0000000..c6d58d7 --- /dev/null +++ b/pages/firstRun.vue @@ -0,0 +1,62 @@ + + + + + + + Initial setup + + + + It looks like you've run the server with an empty or uninitialized database or with database without any users. + Below you can initialize the database register your first user and. + + { formValue[k] = v }" + /> + + + + Initialize + + + + diff --git a/pages/login.vue b/pages/login.vue index 5761adf..0667932 100644 --- a/pages/login.vue +++ b/pages/login.vue @@ -19,6 +19,7 @@ const redirectTo = ref(route.redirectedFrom); definePageMeta({ layout: false, + middleware: ["first-run"], }); async function submit() { diff --git a/schemaModel.sql b/schemaModel.sql new file mode 100644 index 0000000..b03f0ac --- /dev/null +++ b/schemaModel.sql @@ -0,0 +1,167 @@ +-- Server version 8.0.32 + +-- +-- Table structure for table `users` +-- + +CREATE TABLE `users` ( + `id` bigint unsigned NOT NULL DEFAULT (((unix_timestamp() * 1000 * pow(2,22)) + floor((rand() * pow(2,12))))), + `username` varchar(30) NOT NULL, + `email` varchar(128) NOT NULL, + `password` binary(64) NOT NULL, + `display_name` varchar(30) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `idusers_UNIQUE` (`id`), + UNIQUE KEY `username_UNIQUE` (`username`), + UNIQUE KEY `email_UNIQUE` (`email`) +); + +-- +-- Table structure for table `clients` +-- + +CREATE TABLE `clients` ( + `id` bigint unsigned NOT NULL DEFAULT (((unix_timestamp() * 1000 * pow(2,22)) + floor((rand() * pow(2,12))))), + `name` varchar(128) DEFAULT NULL, + `address` varchar(128) DEFAULT NULL, + `phone` varchar(16) DEFAULT NULL, + `email` varchar(128) DEFAULT NULL, + PRIMARY KEY (`id`) +); + +-- +-- Table structure for table `orders` +-- + +CREATE TABLE `orders` ( + `id` bigint unsigned NOT NULL DEFAULT (((unix_timestamp() * 1000 * pow(2,22)) + floor((rand() * pow(2,12))))), + `client` bigint unsigned NOT NULL, + `user` bigint unsigned NOT NULL, + `is_draft` tinyint NOT NULL DEFAULT '1', + PRIMARY KEY (`id`), + KEY `user_idx` (`user`), + KEY `client_idx` (`client`), + CONSTRAINT `client` FOREIGN KEY (`client`) REFERENCES `clients` (`id`), + CONSTRAINT `user` FOREIGN KEY (`user`) REFERENCES `users` (`id`) +); + +-- +-- Table structure for table `imported_products` +-- + +CREATE TABLE `imported_products` ( + `id` bigint unsigned NOT NULL DEFAULT (((unix_timestamp() * 1000 * pow(2,22)) + floor((rand() * pow(2,12))))), + `order` bigint unsigned NOT NULL, + `name` varchar(128) DEFAULT NULL, + `link` varchar(1024) NOT NULL, + `price_imported` decimal(10,2) NOT NULL DEFAULT '0.00', + `price` decimal(10,2) NOT NULL DEFAULT '0.00', + PRIMARY KEY (`id`), + KEY `order_idx` (`order`), + CONSTRAINT `order2` FOREIGN KEY (`order`) REFERENCES `orders` (`id`) +); + +-- +-- Table structure for table `offer` +-- + +CREATE TABLE `offer` ( + `id` bigint unsigned NOT NULL DEFAULT (((unix_timestamp() * 1000 * pow(2,22)) + floor((rand() * pow(2,12))))), + `name` varchar(45) NOT NULL, + `description` text, + `recommended_price` decimal(10,2) DEFAULT NULL, + PRIMARY KEY (`id`) +); + +-- +-- Table structure for table `order_templates` +-- + +CREATE TABLE `order_templates` ( + `id` bigint unsigned NOT NULL DEFAULT (((unix_timestamp() * 1000 * pow(2,22)) + floor((rand() * pow(2,12))))), + `name` varchar(45) NOT NULL, + `description` text, + PRIMARY KEY (`id`) +); + +-- +-- Table structure for table `sessions` +-- + +CREATE TABLE `sessions` ( + `id` bigint unsigned NOT NULL DEFAULT (((unix_timestamp() * 1000 * pow(2,22)) + floor((rand() * pow(2,12))))), + `user` bigint unsigned NOT NULL, + `expiry_date` timestamp NULL DEFAULT ((now() + interval 30 day)), + PRIMARY KEY (`id`), + KEY `user_idx` (`user`), + CONSTRAINT `user_session` FOREIGN KEY (`user`) REFERENCES `users` (`id`) +); + +-- +-- Table structure for table `work` +-- + +CREATE TABLE `work` ( + `id` bigint unsigned NOT NULL DEFAULT (((unix_timestamp() * 1000 * pow(2,22)) + floor((rand() * pow(2,12))))), + `order` bigint unsigned NOT NULL, + `offer` bigint unsigned NOT NULL, + `price` decimal(10,2) NOT NULL, + `notes` text, + `is_fulfilled` tinyint NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + KEY `order_idx` (`order`), + KEY `offer_idx` (`offer`), + CONSTRAINT `offer` FOREIGN KEY (`offer`) REFERENCES `offer` (`id`), + CONSTRAINT `order` FOREIGN KEY (`order`) REFERENCES `orders` (`id`) +); + +-- +-- Table structure for table `work_templates` +-- + +CREATE TABLE `work_templates` ( + `id` bigint unsigned NOT NULL DEFAULT (((unix_timestamp() * 1000 * pow(2,22)) + floor((rand() * pow(2,12))))), + `order_template` bigint unsigned NOT NULL, + `offer` bigint unsigned NOT NULL, + `price` decimal(10,2) NOT NULL DEFAULT '0.00', + `notes` text, + PRIMARY KEY (`id`), + KEY `order_template_idx` (`order_template`), + KEY `offer_idx` (`offer`), + CONSTRAINT `offer2` FOREIGN KEY (`offer`) REFERENCES `offer` (`id`), + CONSTRAINT `order_template` FOREIGN KEY (`order_template`) REFERENCES `order_templates` (`id`) +); + +-- +-- Final view structure for view `orderSummaries` +-- + +CREATE VIEW `orderSummaries` AS +SELECT + `id`, + `client`, + `user`, + `is_draft`, + (COALESCE(`imported_products`.`price`, 0) + COALESCE(`work`.`price`, 0)) AS `value`, + COALESCE(`imported_products`.`count`, 0) as `imported_products_count`, + COALESCE(`work`.`count`, 0) as `work_count` +FROM +`orders` +LEFT JOIN +( + SELECT + `order`, + SUM(`price`) as `price`, + COUNT(*) AS `count` + FROM `imported_products` + GROUP BY `order` +) as `imported_products` ON `orders`.`id` = `imported_products`.`order` +LEFT JOIN +( + SELECT + `order`, + SUM(`price`) AS `price`, + COUNT(*) AS `count` + FROM `work` + GROUP BY `work`.`order` +) AS `work` ON `work`.`order` = `orders`.`id`; diff --git a/server/api/firstRun.get.ts b/server/api/firstRun.get.ts new file mode 100644 index 0000000..ae1bb23 --- /dev/null +++ b/server/api/firstRun.get.ts @@ -0,0 +1,15 @@ +/* global defineEventHandler */ +import { data, database } from "../utils/database"; + +export async function isFirstRun() { + const [tables] = await database.query({ sql: "SHOW TABLES", rowsAsArray: true }, []) as data<[string]>; + if (tables.length === 0) return true; + if (!tables.find(a => a[0] === "users")) return true; + const [[users]] = await database.query("SELECT COUNT(*) as `count` FROM `users`") as data<{count: number}>; + if (users.count === 0) return true; + return false; +} + +export default defineEventHandler((e) => { + return isFirstRun(); +}); diff --git a/server/api/firstRun.post.ts b/server/api/firstRun.post.ts new file mode 100644 index 0000000..657b8d5 --- /dev/null +++ b/server/api/firstRun.post.ts @@ -0,0 +1,33 @@ +/* global defineEventHandler, setResponseStatus, readBody, createError */ + +import fs from "node:fs/promises"; + +import { database as db } from "../utils/database"; +import { isFirstRun } from "./firstRun.get"; +import { getPasswordHash } from "./login.post"; +import Snowflake from "~/utils/snowflake"; + +export default defineEventHandler(async (e) => { + if (!isFirstRun()) { + setResponseStatus(e, 404); + return ""; + } + + const body = await readBody(e); + if (typeof body !== "object") throw createError({ message: "Invalid body", statusCode: 400 }); + const username = body.username; + if (typeof username !== "string") throw createError({ message: "username is not string", statusCode: 400 }); + const password = body.password; + if (typeof password !== "string") throw createError({ message: "password is not string", statusCode: 400 }); + const email = body.email; + if (typeof email !== "string") throw createError({ message: "email is not string", statusCode: 400 }); + + const sql = await fs.readFile("./schemaModel.sql", "utf-8"); + + const database = await db.new({ multipleStatements: true }); + await database.query(sql); + await database.execute( + "INSERT INTO `users` (`id`, `username`, `password`, `email`) VALUES (?, ?, ?, ?)", + [new Snowflake().toString(), username, getPasswordHash(password), email]); + return ""; +});
+ It looks like you've run the server with an empty or uninitialized database or with database without any users. + Below you can initialize the database register your first user and. +