diff --git a/src/app/app.vue b/src/app/app.vue
index 2e1e6be4..d05c1503 100644
--- a/src/app/app.vue
+++ b/src/app/app.vue
@@ -1,14 +1,12 @@
-
-
-
+
+
-
-
-
+
+
diff --git a/src/app/components/setup/welcome.vue b/src/app/components/setup/welcome.vue
deleted file mode 100644
index f69f6e0a..00000000
--- a/src/app/components/setup/welcome.vue
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
- {{ $t('setup.messageWelcome.whatIs') }}
-
-
- {{ $t('setup.messageWelcome.warning') }}
-
-
- {{ $t('setup.messageWelcome.next') }}
-
-
-
-
-
diff --git a/src/app/layouts/Footer.vue b/src/app/layouts/Footer.vue
deleted file mode 100644
index 7d9fbbd2..00000000
--- a/src/app/layouts/Footer.vue
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-
diff --git a/src/app/layouts/Header.vue b/src/app/layouts/Header.vue
deleted file mode 100644
index 30335870..00000000
--- a/src/app/layouts/Header.vue
+++ /dev/null
@@ -1,111 +0,0 @@
-
-
-
-
-
diff --git a/src/app/layouts/default.vue b/src/app/layouts/default.vue
new file mode 100644
index 00000000..e11354c6
--- /dev/null
+++ b/src/app/layouts/default.vue
@@ -0,0 +1,146 @@
+
+
+
+
+
diff --git a/src/app/layouts/setup.vue b/src/app/layouts/setup.vue
new file mode 100644
index 00000000..76d08eca
--- /dev/null
+++ b/src/app/layouts/setup.vue
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+ {{ $t('setup.welcome') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/pages/setup.vue b/src/app/pages/setup.vue
deleted file mode 100644
index cfd19e46..00000000
--- a/src/app/pages/setup.vue
+++ /dev/null
@@ -1,142 +0,0 @@
-
-
-
-
-
-
- {{ $t('setup.welcome') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/app/components/setup/lang.vue b/src/app/pages/setup/1.vue
similarity index 73%
rename from src/app/components/setup/lang.vue
rename to src/app/pages/setup/1.vue
index ce7fbb56..fd4a0fca 100644
--- a/src/app/components/setup/lang.vue
+++ b/src/app/pages/setup/1.vue
@@ -6,40 +6,34 @@
+ Continue
diff --git a/src/app/pages/setup/3.vue b/src/app/pages/setup/3.vue
new file mode 100644
index 00000000..cdbe69f3
--- /dev/null
+++ b/src/app/pages/setup/3.vue
@@ -0,0 +1,16 @@
+
+
+
+ {{ $t('setup.messageWelcome.whatIs') }}
+
+
Continue
+
+
+
+
diff --git a/src/app/components/setup/adminUser.vue b/src/app/pages/setup/4.vue
similarity index 65%
rename from src/app/components/setup/adminUser.vue
rename to src/app/pages/setup/4.vue
index f3bedaa2..06d92864 100644
--- a/src/app/components/setup/adminUser.vue
+++ b/src/app/pages/setup/4.vue
@@ -12,7 +12,7 @@
form="newAccount"
type="text"
autocomplete="username"
- :class="inputClass"
+ class="px-3 py-2 text-sm dark:bg-neutral-700 text-gray-500 dark:text-gray-200 mb-5 border-2 border-gray-100 dark:border-neutral-800 rounded-lg w-full focus:border-red-800 dark:focus:border-red-800 dark:placeholder:text-neutral-400 focus:outline-0 focus:ring-0"
/>
@@ -23,7 +23,7 @@
form="newAccount"
type="password"
autocomplete="new-password"
- :class="inputClass"
+ class="px-3 py-2 text-sm dark:bg-neutral-700 text-gray-500 dark:text-gray-200 mb-5 border-2 border-gray-100 dark:border-neutral-800 rounded-lg w-full focus:border-red-800 dark:focus:border-red-800 dark:placeholder:text-neutral-400 focus:outline-0 focus:ring-0"
/>
@@ -36,33 +36,21 @@
class="ml-2"
/>
+ Create Account
-
diff --git a/src/app/stores/setup.ts b/src/app/stores/setup.ts
index 6ea61e74..ba7224e3 100644
--- a/src/app/stores/setup.ts
+++ b/src/app/stores/setup.ts
@@ -25,5 +25,31 @@ export const useSetupStore = defineStore('Setup', () => {
return response.success;
}
- return { signup, updateHostPort, runMigration };
+ type SetupError = {
+ title: string;
+ message: string;
+ };
+
+ const error = ref(null);
+
+ function handleError(e: SetupError) {
+ error.value = e;
+ }
+
+ const step = ref(1);
+ const totalSteps = ref(6);
+ function setStep(i: number) {
+ step.value = i;
+ }
+
+ return {
+ signup,
+ updateHostPort,
+ runMigration,
+ error,
+ handleError,
+ step,
+ totalSteps,
+ setStep,
+ };
});
diff --git a/src/app/utils/api.ts b/src/app/utils/api.ts
index 206d6a86..0dda4d85 100644
--- a/src/app/utils/api.ts
+++ b/src/app/utils/api.ts
@@ -131,14 +131,14 @@ class API {
password: string;
accept: boolean;
}) {
- return $fetch('/api/account/setup', {
+ return $fetch('/api/setup/account', {
method: 'post',
body: { username, password, accept },
});
}
async setupHostPort({ host, port }: { host: string; port: number }) {
- return $fetch('/api/admin/hostport', {
+ return $fetch('/api/setup/hostport', {
method: 'post',
body: { host, port },
});
diff --git a/src/server/api/account/setup.post.ts b/src/server/api/setup/account.post.ts
similarity index 77%
rename from src/server/api/account/setup.post.ts
rename to src/server/api/setup/account.post.ts
index f70749a1..b1329b9a 100644
--- a/src/server/api/account/setup.post.ts
+++ b/src/server/api/setup/account.post.ts
@@ -3,13 +3,14 @@ export default defineEventHandler(async (event) => {
event,
validateZod(passwordSetupType, event)
);
- const users = await Database.user.findAll();
- if (users.length !== 0) {
+ const setupDone = await Database.setup.done();
+ if (setupDone) {
throw createError({
statusCode: 400,
statusMessage: 'Invalid state',
});
}
await Database.user.create(username, password);
+ await Database.setup.set(5);
return { success: true };
});
diff --git a/src/server/api/setup/hostport.post.ts b/src/server/api/setup/hostport.post.ts
new file mode 100644
index 00000000..0704fbe4
--- /dev/null
+++ b/src/server/api/setup/hostport.post.ts
@@ -0,0 +1,16 @@
+export default defineEventHandler(async (event) => {
+ const { host, port } = await readValidatedBody(
+ event,
+ validateZod(hostPortType, event)
+ );
+ const setupDone = await Database.setup.done();
+ if (setupDone) {
+ throw createError({
+ statusCode: 400,
+ statusMessage: 'Invalid state',
+ });
+ }
+ await Database.system.updateClientsHostPort(host, port);
+ await Database.setup.set('success');
+ return { success: true };
+});
diff --git a/src/server/middleware/session.ts b/src/server/middleware/session.ts
index a03e0a96..b10d880a 100644
--- a/src/server/middleware/session.ts
+++ b/src/server/middleware/session.ts
@@ -6,7 +6,7 @@ export default defineEventHandler(async (event) => {
// Handle api routes
if (
!url.pathname.startsWith('/api/') ||
- url.pathname === '/api/account/setup' ||
+ url.pathname.startsWith('/api/setup/') ||
url.pathname === '/api/session' ||
url.pathname === '/api/lang' ||
url.pathname === '/api/release' ||
diff --git a/src/server/middleware/setup.ts b/src/server/middleware/setup.ts
index 5377895f..78a86858 100644
--- a/src/server/middleware/setup.ts
+++ b/src/server/middleware/setup.ts
@@ -7,22 +7,21 @@ export default defineEventHandler(async (event) => {
return;
}
- const users = await Database.user.findAll();
- if (users.length === 0) {
- // If not setup
- if (url.pathname.startsWith('/setup')) {
- return;
+ const setupDone = await Database.setup.done();
+ if (!setupDone) {
+ const parsedSetup = url.pathname.match(/\/setup\/(\d)/);
+ if (!parsedSetup) {
+ return sendRedirect(event, `/setup/1`, 302);
}
- if (url.pathname.startsWith('/api/')) {
- throw createError({
- statusCode: 400,
- statusMessage: 'Invalid State',
- });
+ const [_, currentSetup] = parsedSetup;
+ const step = await Database.setup.get();
+ if (step.toString() === currentSetup) {
+ return;
}
- return sendRedirect(event, '/setup', 302);
+ return sendRedirect(event, `/setup/${step}`, 302);
} else {
// If already set up
- if (!url.pathname.startsWith('/setup')) {
+ if (!url.pathname.startsWith('/setup/')) {
return;
}
return sendRedirect(event, '/login', 302);
diff --git a/src/services/database/lowdb.ts b/src/services/database/lowdb.ts
index 5acc55fd..f6e8f7be 100644
--- a/src/services/database/lowdb.ts
+++ b/src/services/database/lowdb.ts
@@ -27,10 +27,35 @@ import {
type Lang,
type Statistics,
} from './repositories/system';
+import { SetupRepository, type Steps } from './repositories/setup';
const DEBUG = debug('LowDB');
-export class LowDBSystem extends SystemRepository {
+export class LowDBSetup extends SetupRepository {
+ #db: Low;
+ constructor(db: Low) {
+ super();
+ this.#db = db;
+ }
+ async done() {
+ if (this.#db.data.setup === 'success') {
+ return true;
+ }
+ return false;
+ }
+
+ async get() {
+ return this.#db.data.setup;
+ }
+
+ async set(step: Steps) {
+ this.#db.update((v) => {
+ v.setup = step;
+ });
+ }
+}
+
+class LowDBSystem extends SystemRepository {
#db: Low;
constructor(db: Low) {
super();
@@ -87,7 +112,7 @@ export class LowDBSystem extends SystemRepository {
}
}
-export class LowDBUser extends UserRepository {
+class LowDBUser extends UserRepository {
#db: Low;
constructor(db: Low) {
super();
@@ -155,7 +180,7 @@ export class LowDBUser extends UserRepository {
}
}
-export class LowDBClient extends ClientRepository {
+class LowDBClient extends ClientRepository {
#db: Low;
constructor(db: Low) {
super();
@@ -252,6 +277,7 @@ export class LowDBClient extends ClientRepository {
export default class LowDB extends DatabaseProvider {
#db: Low;
+ setup: LowDBSetup;
system: LowDBSystem;
user: LowDBUser;
client: LowDBClient;
@@ -259,6 +285,7 @@ export default class LowDB extends DatabaseProvider {
private constructor(db: Low) {
super();
this.#db = db;
+ this.setup = new LowDBSetup(this.#db);
this.system = new LowDBSystem(this.#db);
this.user = new LowDBUser(this.#db);
this.client = new LowDBClient(this.#db);
diff --git a/src/services/database/migrations/1.ts b/src/services/database/migrations/1.ts
index 20575cdc..79f9f60f 100644
--- a/src/services/database/migrations/1.ts
+++ b/src/services/database/migrations/1.ts
@@ -15,6 +15,7 @@ export async function run1(db: Low) {
const database: Database = {
migrations: [],
+ setup: 1,
system: {
general: {
sessionTimeout: 3600, // 1 hour
diff --git a/src/services/database/repositories/database.ts b/src/services/database/repositories/database.ts
index dfbaee21..adaaacd0 100644
--- a/src/services/database/repositories/database.ts
+++ b/src/services/database/repositories/database.ts
@@ -1,10 +1,12 @@
import type { ClientRepository, Client } from './client';
+import type { SetupRepository, Steps } from './setup';
import type { System, SystemRepository } from './system';
import type { User, UserRepository } from './user';
// Represent data structure
export type Database = {
migrations: string[];
+ setup: Steps;
system: System;
users: User[];
clients: Record;
@@ -12,6 +14,7 @@ export type Database = {
export const DEFAULT_DATABASE: Database = {
migrations: [],
+ setup: 1,
system: null as never,
users: [],
clients: {},
@@ -37,6 +40,7 @@ export abstract class DatabaseProvider {
*/
abstract disconnect(): Promise;
+ abstract setup: SetupRepository;
abstract system: SystemRepository;
abstract user: UserRepository;
abstract client: ClientRepository;
diff --git a/src/services/database/repositories/setup.ts b/src/services/database/repositories/setup.ts
new file mode 100644
index 00000000..a6adeba8
--- /dev/null
+++ b/src/services/database/repositories/setup.ts
@@ -0,0 +1,11 @@
+export type Steps = 1 | 2 | 3 | 4 | 5 | 'success';
+
+/**
+ * Interface for setup-related database operations.
+ * This interface provides methods for managing setup data.
+ */
+export abstract class SetupRepository {
+ abstract done(): Promise;
+ abstract get(): Promise;
+ abstract set(step: Steps): Promise;
+}