Fix login, registration and made the first database version.

This commit is contained in:
Peaceultime 2024-11-05 19:51:56 +01:00
parent 83ddaf19d4
commit 1af78e5ab7
35 changed files with 180 additions and 391 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -1,6 +1,6 @@
<template> <template>
<ToastRoot :default-open="open" :duration="duration" class="ToastRoot bg-light-10 dark:bg-dark-10 border border-light-30 dark:border-dark-30" v-model:open="model"> <ToastRoot :default-open="open" :duration="duration" class="ToastRoot bg-light-10 dark:bg-dark-10 border border-light-30 dark:border-dark-30" v-model:open="model">
<div class="grid grid-cols-8 px-3 pt-1 pb-2"> <div class="grid grid-cols-8 px-3 pt-2 pb-2">
<ToastTitle v-if="title" class="font-semibold text-xl col-span-7 text-light-70 dark:text-dark-70" asChild><h4>{{ title }}</h4></ToastTitle> <ToastTitle v-if="title" class="font-semibold text-xl col-span-7 text-light-70 dark:text-dark-70" asChild><h4>{{ title }}</h4></ToastTitle>
<ToastClose v-if="closeable" aria-label="Close" class="text-xl -translate-y-2 translate-x-4 cursor-pointer"><span aria-hidden>×</span></ToastClose> <ToastClose v-if="closeable" aria-label="Close" class="text-xl -translate-y-2 translate-x-4 cursor-pointer"><span aria-hidden>×</span></ToastClose>
<ToastDescription v-if="content" class="text-sm col-span-8 text-light-70 dark:text-dark-70" asChild><span>{{ content }}</span></ToastDescription> <ToastDescription v-if="content" class="text-sm col-span-8 text-light-70 dark:text-dark-70" asChild><span>{{ content }}</span></ToastDescription>

View File

@ -1,4 +1,3 @@
import ".dotenv/config";
import { Database } from "bun:sqlite"; import { Database } from "bun:sqlite";
import { drizzle } from "drizzle-orm/bun-sqlite"; import { drizzle } from "drizzle-orm/bun-sqlite";
import * as schema from '../db/schema'; import * as schema from '../db/schema';

BIN
db.sqlite

Binary file not shown.

BIN
db.sqlite-shm Normal file

Binary file not shown.

BIN
db.sqlite-wal Normal file

Binary file not shown.

View File

@ -24,6 +24,15 @@ export const userSessionsTable = sqliteTable("user_sessions", {
} }
}); });
export const userPermissionsTable = sqliteTable("user_permissions", {
id: int().notNull().references(() => usersTable.id, { onDelete: 'cascade', onUpdate: 'cascade' }),
permissions: text().notNull(),
}, (table): SQLiteTableExtraConfig => {
return {
pk: primaryKey({ columns: [table.id, table.permissions] }),
}
});
export const explorerContentTable = sqliteTable("explorer_content", { export const explorerContentTable = sqliteTable("explorer_content", {
path: text().primaryKey(), path: text().primaryKey(),
owner: int().notNull().references(() => usersTable.id, { onDelete: 'cascade', onUpdate: 'cascade' }), owner: int().notNull().references(() => usersTable.id, { onDelete: 'cascade', onUpdate: 'cascade' }),
@ -37,6 +46,7 @@ export const explorerContentTable = sqliteTable("explorer_content", {
export const usersRelation = relations(usersTable, ({one, many}) => ({ export const usersRelation = relations(usersTable, ({one, many}) => ({
data: one(usersDataTable, { fields: [usersTable.id], references: [usersDataTable.id], }), data: one(usersDataTable, { fields: [usersTable.id], references: [usersDataTable.id], }),
session: many(userSessionsTable), session: many(userSessionsTable),
permission: many(userPermissionsTable),
content: many(explorerContentTable), content: many(explorerContentTable),
})); }));
export const usersDataRelation = relations(usersDataTable, ({one}) => ({ export const usersDataRelation = relations(usersDataTable, ({one}) => ({
@ -45,6 +55,9 @@ export const usersDataRelation = relations(usersDataTable, ({one}) => ({
export const userSessionsRelation = relations(userSessionsTable, ({one}) => ({ export const userSessionsRelation = relations(userSessionsTable, ({one}) => ({
users: one(usersTable, { fields: [userSessionsTable.user_id], references: [usersTable.id], }), users: one(usersTable, { fields: [userSessionsTable.user_id], references: [usersTable.id], }),
})); }));
export const userPermissionsRelation = relations(userPermissionsTable, ({ one }) => ({
users: one(usersTable, { fields: [userPermissionsTable.id], references: [usersTable.id], }),
}));
export const explorerContentRelation = relations(explorerContentTable, ({ one }) => ({ export const explorerContentRelation = relations(explorerContentTable, ({ one }) => ({
users: one(usersTable, { fields: [explorerContentTable.owner], references: [usersTable.id], }), users: one(usersTable, { fields: [explorerContentTable.owner], references: [usersTable.id], }),
})); }));

View File

@ -1,6 +1,3 @@
-- Current sql file was generated after introspecting the database
-- If you want to run this migration please uncomment this code before executing migrations
/*
CREATE TABLE `explorer_content` ( CREATE TABLE `explorer_content` (
`path` text PRIMARY KEY NOT NULL, `path` text PRIMARY KEY NOT NULL,
`owner` integer NOT NULL, `owner` integer NOT NULL,
@ -22,6 +19,7 @@ CREATE TABLE `user_sessions` (
--> statement-breakpoint --> statement-breakpoint
CREATE TABLE `users_data` ( CREATE TABLE `users_data` (
`id` integer PRIMARY KEY NOT NULL, `id` integer PRIMARY KEY NOT NULL,
`signin` integer NOT NULL,
FOREIGN KEY (`id`) REFERENCES `users`(`id`) ON UPDATE cascade ON DELETE cascade FOREIGN KEY (`id`) REFERENCES `users`(`id`) ON UPDATE cascade ON DELETE cascade
); );
--> statement-breakpoint --> statement-breakpoint
@ -30,14 +28,9 @@ CREATE TABLE `users` (
`username` text NOT NULL, `username` text NOT NULL,
`email` text NOT NULL, `email` text NOT NULL,
`hash` text NOT NULL, `hash` text NOT NULL,
`state` integer DEFAULT 0 `state` integer DEFAULT 0 NOT NULL
); );
--> statement-breakpoint --> statement-breakpoint
CREATE UNIQUE INDEX `users_hash_unique` ON `users` (`hash`);--> statement-breakpoint
CREATE UNIQUE INDEX `users_email_unique` ON `users` (`email`);--> statement-breakpoint
CREATE UNIQUE INDEX `users_username_unique` ON `users` (`username`);--> statement-breakpoint CREATE UNIQUE INDEX `users_username_unique` ON `users` (`username`);--> statement-breakpoint
CREATE TABLE `__drizzle_migrations` ( CREATE UNIQUE INDEX `users_email_unique` ON `users` (`email`);--> statement-breakpoint
CREATE UNIQUE INDEX `users_hash_unique` ON `users` (`hash`);
);
*/

View File

@ -1,18 +0,0 @@
DROP TABLE `__drizzle_migrations`;--> statement-breakpoint
PRAGMA foreign_keys=OFF;--> statement-breakpoint
CREATE TABLE `__new_users` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`username` text NOT NULL,
`email` text NOT NULL,
`hash` text NOT NULL,
`state` integer DEFAULT 0 NOT NULL
);
--> statement-breakpoint
INSERT INTO `__new_users`("id", "username", "email", "hash", "state") SELECT "id", "username", "email", "hash", "state" FROM `users`;--> statement-breakpoint
DROP TABLE `users`;--> statement-breakpoint
ALTER TABLE `__new_users` RENAME TO `users`;--> statement-breakpoint
PRAGMA foreign_keys=ON;--> statement-breakpoint
CREATE UNIQUE INDEX `users_username_unique` ON `users` (`username`);--> statement-breakpoint
CREATE UNIQUE INDEX `users_email_unique` ON `users` (`email`);--> statement-breakpoint
CREATE UNIQUE INDEX `users_hash_unique` ON `users` (`hash`);--> statement-breakpoint
ALTER TABLE `users_data` ADD `signin` integer NOT NULL;

View File

@ -0,0 +1,6 @@
CREATE TABLE `user_permissions` (
`id` integer NOT NULL,
`permissions` text NOT NULL,
PRIMARY KEY(`id`, `permissions`),
FOREIGN KEY (`id`) REFERENCES `users`(`id`) ON UPDATE cascade ON DELETE cascade
);

View File

@ -1,65 +1,64 @@
{ {
"id": "00000000-0000-0000-0000-000000000000",
"prevId": "",
"version": "6", "version": "6",
"dialect": "sqlite", "dialect": "sqlite",
"id": "f66f1f97-ceb3-46ed-988b-62828fe4a6a6",
"prevId": "00000000-0000-0000-0000-000000000000",
"tables": { "tables": {
"explorer_content": { "explorer_content": {
"name": "explorer_content", "name": "explorer_content",
"columns": { "columns": {
"path": { "path": {
"autoincrement": false,
"name": "path", "name": "path",
"type": "text", "type": "text",
"primaryKey": true, "primaryKey": true,
"notNull": true "notNull": true,
"autoincrement": false
}, },
"owner": { "owner": {
"autoincrement": false,
"name": "owner", "name": "owner",
"type": "integer", "type": "integer",
"primaryKey": false, "primaryKey": false,
"notNull": true "notNull": true,
"autoincrement": false
}, },
"title": { "title": {
"autoincrement": false,
"name": "title", "name": "title",
"type": "text", "type": "text",
"primaryKey": false, "primaryKey": false,
"notNull": true "notNull": true,
"autoincrement": false
}, },
"type": { "type": {
"autoincrement": false,
"name": "type", "name": "type",
"type": "text", "type": "text",
"primaryKey": false, "primaryKey": false,
"notNull": true "notNull": true,
"autoincrement": false
}, },
"content": { "content": {
"autoincrement": false,
"name": "content", "name": "content",
"type": "blob", "type": "blob",
"primaryKey": false, "primaryKey": false,
"notNull": false "notNull": false,
"autoincrement": false
}, },
"navigable": { "navigable": {
"default": true,
"autoincrement": false,
"name": "navigable", "name": "navigable",
"type": "integer", "type": "integer",
"primaryKey": false, "primaryKey": false,
"notNull": false "notNull": false,
"autoincrement": false,
"default": true
}, },
"private": { "private": {
"default": false,
"autoincrement": false,
"name": "private", "name": "private",
"type": "integer", "type": "integer",
"primaryKey": false, "primaryKey": false,
"notNull": false "notNull": false,
"autoincrement": false,
"default": false
} }
}, },
"compositePrimaryKeys": {},
"indexes": {}, "indexes": {},
"foreignKeys": { "foreignKeys": {
"explorer_content_owner_users_id_fk": { "explorer_content_owner_users_id_fk": {
@ -76,6 +75,7 @@
"onUpdate": "cascade" "onUpdate": "cascade"
} }
}, },
"compositePrimaryKeys": {},
"uniqueConstraints": {}, "uniqueConstraints": {},
"checkConstraints": {} "checkConstraints": {}
}, },
@ -83,34 +83,25 @@
"name": "user_sessions", "name": "user_sessions",
"columns": { "columns": {
"id": { "id": {
"autoincrement": false,
"name": "id", "name": "id",
"type": "integer", "type": "integer",
"primaryKey": false, "primaryKey": false,
"notNull": true "notNull": true,
"autoincrement": false
}, },
"user_id": { "user_id": {
"autoincrement": false,
"name": "user_id", "name": "user_id",
"type": "integer", "type": "integer",
"primaryKey": false, "primaryKey": false,
"notNull": true "notNull": true,
"autoincrement": false
}, },
"timestamp": { "timestamp": {
"autoincrement": false,
"name": "timestamp", "name": "timestamp",
"type": "integer", "type": "integer",
"primaryKey": false, "primaryKey": false,
"notNull": true "notNull": true,
} "autoincrement": false
},
"compositePrimaryKeys": {
"user_sessions_id_user_id_pk": {
"columns": [
"id",
"user_id"
],
"name": "user_sessions_id_user_id_pk"
} }
}, },
"indexes": {}, "indexes": {},
@ -129,6 +120,15 @@
"onUpdate": "cascade" "onUpdate": "cascade"
} }
}, },
"compositePrimaryKeys": {
"user_sessions_id_user_id_pk": {
"columns": [
"id",
"user_id"
],
"name": "user_sessions_id_user_id_pk"
}
},
"uniqueConstraints": {}, "uniqueConstraints": {},
"checkConstraints": {} "checkConstraints": {}
}, },
@ -136,14 +136,20 @@
"name": "users_data", "name": "users_data",
"columns": { "columns": {
"id": { "id": {
"autoincrement": false,
"name": "id", "name": "id",
"type": "integer", "type": "integer",
"primaryKey": true, "primaryKey": true,
"notNull": true "notNull": true,
"autoincrement": false
},
"signin": {
"name": "signin",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
} }
}, },
"compositePrimaryKeys": {},
"indexes": {}, "indexes": {},
"foreignKeys": { "foreignKeys": {
"users_data_id_users_id_fk": { "users_data_id_users_id_fk": {
@ -160,6 +166,7 @@
"onUpdate": "cascade" "onUpdate": "cascade"
} }
}, },
"compositePrimaryKeys": {},
"uniqueConstraints": {}, "uniqueConstraints": {},
"checkConstraints": {} "checkConstraints": {}
}, },
@ -167,48 +174,47 @@
"name": "users", "name": "users",
"columns": { "columns": {
"id": { "id": {
"autoincrement": true,
"name": "id", "name": "id",
"type": "integer", "type": "integer",
"primaryKey": true, "primaryKey": true,
"notNull": true "notNull": true,
"autoincrement": true
}, },
"username": { "username": {
"autoincrement": false,
"name": "username", "name": "username",
"type": "text", "type": "text",
"primaryKey": false, "primaryKey": false,
"notNull": true "notNull": true,
"autoincrement": false
}, },
"email": { "email": {
"autoincrement": false,
"name": "email", "name": "email",
"type": "text", "type": "text",
"primaryKey": false, "primaryKey": false,
"notNull": true "notNull": true,
"autoincrement": false
}, },
"hash": { "hash": {
"autoincrement": false,
"name": "hash", "name": "hash",
"type": "text", "type": "text",
"primaryKey": false, "primaryKey": false,
"notNull": true "notNull": true,
"autoincrement": false
}, },
"state": { "state": {
"default": 0,
"autoincrement": false,
"name": "state", "name": "state",
"type": "integer", "type": "integer",
"primaryKey": false, "primaryKey": false,
"notNull": false "notNull": true,
"autoincrement": false,
"default": 0
} }
}, },
"compositePrimaryKeys": {},
"indexes": { "indexes": {
"users_hash_unique": { "users_username_unique": {
"name": "users_hash_unique", "name": "users_username_unique",
"columns": [ "columns": [
"hash" "username"
], ],
"isUnique": true "isUnique": true
}, },
@ -219,24 +225,16 @@
], ],
"isUnique": true "isUnique": true
}, },
"users_username_unique": { "users_hash_unique": {
"name": "users_username_unique", "name": "users_hash_unique",
"columns": [ "columns": [
"username" "hash"
], ],
"isUnique": true "isUnique": true
} }
}, },
"foreignKeys": {}, "foreignKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"__drizzle_migrations": {
"name": "__drizzle_migrations",
"columns": {},
"compositePrimaryKeys": {}, "compositePrimaryKeys": {},
"indexes": {},
"foreignKeys": {},
"uniqueConstraints": {}, "uniqueConstraints": {},
"checkConstraints": {} "checkConstraints": {}
} }
@ -247,5 +245,8 @@
"schemas": {}, "schemas": {},
"tables": {}, "tables": {},
"columns": {} "columns": {}
},
"internal": {
"indexes": {}
} }
} }

View File

@ -1,8 +1,8 @@
{ {
"version": "6", "version": "6",
"dialect": "sqlite", "dialect": "sqlite",
"id": "0cca5664-1a0e-48ef-b70a-966b7a8142c7", "id": "854cab71-b937-4f4f-80b0-cbb09c7b5944",
"prevId": "00000000-0000-0000-0000-000000000000", "prevId": "f66f1f97-ceb3-46ed-988b-62828fe4a6a6",
"tables": { "tables": {
"explorer_content": { "explorer_content": {
"name": "explorer_content", "name": "explorer_content",
@ -79,6 +79,52 @@
"uniqueConstraints": {}, "uniqueConstraints": {},
"checkConstraints": {} "checkConstraints": {}
}, },
"user_permissions": {
"name": "user_permissions",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"permissions": {
"name": "permissions",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"user_permissions_id_users_id_fk": {
"name": "user_permissions_id_users_id_fk",
"tableFrom": "user_permissions",
"tableTo": "users",
"columnsFrom": [
"id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "cascade"
}
},
"compositePrimaryKeys": {
"user_permissions_id_permissions_pk": {
"columns": [
"id",
"permissions"
],
"name": "user_permissions_id_permissions_pk"
}
},
"uniqueConstraints": {},
"checkConstraints": {}
},
"user_sessions": { "user_sessions": {
"name": "user_sessions", "name": "user_sessions",
"columns": { "columns": {

View File

@ -5,15 +5,15 @@
{ {
"idx": 0, "idx": 0,
"version": "6", "version": "6",
"when": 1730822816801, "when": 1730829864576,
"tag": "0000_lonely_the_renegades", "tag": "0000_needy_rictor",
"breakpoints": true "breakpoints": true
}, },
{ {
"idx": 1, "idx": 1,
"version": "6", "version": "6",
"when": 1730826510693, "when": 1730832678255,
"tag": "0001_lush_selene", "tag": "0001_sticky_jack_flag",
"breakpoints": true "breakpoints": true
} }
] ]

View File

@ -1,29 +0,0 @@
import { relations } from "drizzle-orm/relations";
import { users, explorerContent, userSessions, usersData } from "./schema";
export const explorerContentRelations = relations(explorerContent, ({one}) => ({
user: one(users, {
fields: [explorerContent.owner],
references: [users.id]
}),
}));
export const usersRelations = relations(users, ({many}) => ({
explorerContents: many(explorerContent),
userSessions: many(userSessions),
usersData: many(usersData),
}));
export const userSessionsRelations = relations(userSessions, ({one}) => ({
user: one(users, {
fields: [userSessions.userId],
references: [users.id]
}),
}));
export const usersDataRelations = relations(usersData, ({one}) => ({
user: one(users, {
fields: [usersData.id],
references: [users.id]
}),
}));

View File

@ -1,46 +0,0 @@
import { sqliteTable, AnySQLiteColumn, foreignKey, text, integer, blob, primaryKey, uniqueIndex } from "drizzle-orm/sqlite-core"
import { sql } from "drizzle-orm"
export const explorerContent = sqliteTable("explorer_content", {
path: text().primaryKey().notNull(),
owner: integer().notNull().references(() => users.id, { onDelete: "cascade", onUpdate: "cascade" } ),
title: text().notNull(),
type: text().notNull(),
content: blob(),
navigable: integer().default(true),
private: integer().default(false),
});
export const userSessions = sqliteTable("user_sessions", {
id: integer().notNull(),
userId: integer("user_id").notNull().references(() => users.id, { onDelete: "cascade", onUpdate: "cascade" } ),
timestamp: integer().notNull(),
},
(table) => {
return {
pk0: primaryKey({ columns: [table.id, table.userId], name: "user_sessions_id_user_id_pk"})
}
});
export const usersData = sqliteTable("users_data", {
id: integer().primaryKey().notNull().references(() => users.id, { onDelete: "cascade", onUpdate: "cascade" } ),
});
export const users = sqliteTable("users", {
id: integer().primaryKey({ autoIncrement: true }).notNull(),
username: text().notNull(),
email: text().notNull(),
hash: text().notNull(),
state: integer().default(0),
},
(table) => {
return {
hashUnique: uniqueIndex("users_hash_unique").on(table.hash),
emailUnique: uniqueIndex("users_email_unique").on(table.email),
usernameUnique: uniqueIndex("users_username_unique").on(table.username),
}
});
export const drizzleMigrations = sqliteTable("__drizzle_migrations", {
});

View File

@ -7,7 +7,6 @@
"@nuxtjs/color-mode": "^3.5.2", "@nuxtjs/color-mode": "^3.5.2",
"@nuxtjs/tailwindcss": "^6.12.2", "@nuxtjs/tailwindcss": "^6.12.2",
"@vueuse/nuxt": "^11.1.0", "@vueuse/nuxt": "^11.1.0",
"dotenv": "^16.4.5",
"drizzle-orm": "^0.35.3", "drizzle-orm": "^0.35.3",
"nuxt": "^3.13.2", "nuxt": "^3.13.2",
"nuxt-security": "^2.0.0", "nuxt-security": "^2.0.0",

View File

@ -1,3 +0,0 @@
<template>
Edit your profile
</template>

View File

@ -4,7 +4,7 @@
</Head> </Head>
<div class="flex flex-1 flex-col justify-center items-center"> <div class="flex flex-1 flex-col justify-center items-center">
<ProseH4>Connexion</ProseH4> <ProseH4>Connexion</ProseH4>
<form @submit="() => submit()" class="flex flex-1 flex-col justify-center items-stretch"> <form @submit.prevent="() => submit()" class="flex flex-1 flex-col justify-center items-stretch">
<TextInput type="text" label="Utilisateur ou email" autocomplete="username" v-model="state.usernameOrEmail"/> <TextInput type="text" label="Utilisateur ou email" autocomplete="username" v-model="state.usernameOrEmail"/>
<TextInput type="password" label="Mot de passe" autocomplete="current-password" v-model="state.password"/> <TextInput type="password" label="Mot de passe" autocomplete="current-password" v-model="state.password"/>
<Button class="border border-light-35 dark:border-dark-35 self-center" :loading="status === 'pending'">Se connecter</Button> <Button class="border border-light-35 dark:border-dark-35 self-center" :loading="status === 'pending'">Se connecter</Button>
@ -47,6 +47,7 @@ async function submit()
if(data.success) if(data.success)
{ {
await refresh(); await refresh();
debugger;
const login = result.value; const login = result.value;
if(!login || !login.success) if(!login || !login.success)

9
pages/user/profile.vue Normal file
View File

@ -0,0 +1,9 @@
<script setup lang="ts">
const { user } = useUserSession();
</script>
<template>
<Head>
<Title>Mon profil</Title>
</Head>
</template>

View File

@ -4,11 +4,11 @@
</Head> </Head>
<div class="flex flex-1 flex-col justify-center items-center"> <div class="flex flex-1 flex-col justify-center items-center">
<ProseH4>Inscription</ProseH4> <ProseH4>Inscription</ProseH4>
<form @submit="() => submit()" class="flex flex-1 flex-col justify-center items-stretch p-4"> <form @submit.prevent="() => submit()" class="flex flex-1 flex-col justify-center items-stretch p-4">
<TextInput type="text" label="Nom d'utilisateur" autocomplete="username" v-model="state.username"/> <TextInput type="text" label="Nom d'utilisateur" autocomplete="username" v-model="state.username"/>
<TextInput type="email" label="Email" autocomplete="email" v-model="state.email"/> <TextInput type="email" label="Email" autocomplete="email" v-model="state.email"/>
<TextInput type="password" label="Mot de passe" autocomplete="new-password" v-model="state.password"/> <TextInput type="password" label="Mot de passe" autocomplete="new-password" v-model="state.password"/>
<div class="flex flex-col font-light border border-light-35 dark:border-dark-35 px-4 py-2 max-w-96"> <div class="flex flex-col font-light border border-light-35 dark:border-dark-35 px-4 py-2 me-4">
<span class="">Votre mot de passe doit respecter les critères de sécurité suivants <span class="">Votre mot de passe doit respecter les critères de sécurité suivants
:</span> :</span>
<span class="px-4" :class="{'text-light-red dark:text-dark-red': !checkedLength}">Entre 8 et 128 <span class="px-4" :class="{'text-light-red dark:text-dark-red': !checkedLength}">Entre 8 et 128
@ -71,7 +71,8 @@ async function submit()
if(data.success) if(data.success)
{ {
await execute() await execute();
debugger;
const login = result.value; const login = result.value;
if(!login || !login.success) if(!login || !login.success)
@ -110,46 +111,3 @@ function handleErrors(error: Error | ZodError)
} }
} }
</script> </script>
<!-- <template>
<Head>
<Title>S'inscrire</Title>
</Head>
<div class="flex flex-1 justify-center items-center">
<div class="p-8 w-[48em] border border-light-35 dark:border-dark-35">
<form class="p-4 bg-light-20 dark:bg-dark-20">
<ProseH4>Inscription</ProseH4>
<InputField type="text" autocomplete="username" v-model="state.username"
placeholder="Entrez un nom d'utilisateur" title="Nom d'utilisateur" :error="usernameError"/>
<InputField type="text" autocomplete="email" v-model="state.email" placeholder="Entrez une addresse mail"
title="Adresse mail" :error="emailError"/>
<InputField type="password" autocomplete="new-password" v-model="state.password"
placeholder="Entrez un mot de passe" title="Mot de passe"
:error="!(checkedLength && checkedLowerUpper && checkedDigit && checkedSymbol)"/>
<div class="flex flex-col font-light">
<span class="">Votre mot de passe doit respecter les critères de sécurité suivants
:</span>
<span class="px-4" :class="{'text-light-red dark:text-dark-red': !checkedLength}">Entre 8 et 128
caractères</span>
<span class="px-4" :class="{'text-light-red dark:text-dark-red': !checkedLowerUpper}">Au moins
une minuscule et une majuscule</span>
<span class="px-4" :class="{'text-light-red dark:text-dark-red': !checkedDigit}">Au moins un
chiffre</span>
<span class="px-4" :class="{'text-light-red dark:text-dark-red': !checkedSymbol}">Au moins un
caractère spécial parmis la liste suivante:
<pre>! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ ] ^ _ ` { | } ~</pre>
</span>
</div>
<InputField type="password" v-model="confirmPassword" placeholder="Confirmer le mot de passe" title="Confirmer le mot de passe" autocomplete="new-password"
:error="confirmPassword === '' || confirmPassword === state.password ? '' : 'Les mots de passe saisies ne sont pas identique'"/>
<span v-if="generalError" class="text-light-red dark:text-dark-red">{{ generalError }}</span>
<button class="m-auto block px-4 py-1 bg-light-20 dark:bg-dark-20 border border-light-40 dark:border-dark-40 hover:border-light-50 dark:hover:border-dark-50 active:relative active:top-[1px]">
<div v-if="status === 'pending'" class="loading"></div>
<template v-else>S'inscrire</template>
</button>
<NuxtLink class="mt-4 text-center block text-sm font-semibold tracking-wide hover:italic" :to="{ path: `/user/login`, force: true }">Vous avez déjà un compte ? Se connecter</NuxtLink>
</form>
</div>
</div>
</template> -->

View File

@ -11,8 +11,8 @@ export default defineCachedEventHandler(async (e) => {
return; return;
} }
const where = ["project = $project"]; const where = [];
const criteria: Record<string, any> = { $project: project }; const criteria: Record<string, any> = { };
if(query && query.path !== undefined) if(query && query.path !== undefined)
{ {

View File

@ -2,22 +2,16 @@ import useDatabase from '~/composables/useDatabase';
import type { CommentedFile, CommentSearch, File } from '~/types/api'; import type { CommentedFile, CommentSearch, File } from '~/types/api';
export default defineCachedEventHandler(async (e) => { export default defineCachedEventHandler(async (e) => {
const project = getRouterParam(e, "projectId");
const path = decodeURIComponent(getRouterParam(e, "path") ?? ''); const path = decodeURIComponent(getRouterParam(e, "path") ?? '');
if(!project)
{
setResponseStatus(e, 404);
return;
}
if(!path) if(!path)
{ {
setResponseStatus(e, 404); setResponseStatus(e, 404);
return; return;
} }
const where = ["project = $project", "path = $path"]; const where = ["path = $path"];
const criteria: Record<string, any> = { $project: project, $path: path }; const criteria: Record<string, any> = { $path: path };
if(where.length > 1) if(where.length > 1)
{ {
@ -37,5 +31,5 @@ export default defineCachedEventHandler(async (e) => {
return; return;
}, { }, {
maxAge: 60*60*24, maxAge: 60*60*24,
getKey: (e) => `file-${getRouterParam(e, "projectId")}-${getRouterParam(e, "path")}` getKey: (e) => `file-${getRouterParam(e, "path")}`
}); });

View File

@ -15,7 +15,7 @@ export default defineEventHandler(async (e) => {
const db = useDatabase(); const db = useDatabase();
const content = db.query(`SELECT "path", "title", "type", "order", "private", "navigable", "owner" FROM explorer_files WHERE project = ?1`).all(project!).sort((a: any, b: any) => a.path.length - b.path.length) as NavigatioNExtension[]; const content = db.query(`SELECT "path", "title", "type", "order", "private", "navigable", "owner" FROM explorer_files`).sort((a: any, b: any) => a.path.length - b.path.length) as NavigatioNExtension[];
if(content.length > 0) if(content.length > 0)
{ {

View File

@ -1,31 +0,0 @@
import useDatabase from '~/composables/useDatabase';
import { ProjectSearch } from '~/types/api';
export default defineEventHandler(async (e) => {
const query = getQuery(e);
const where = ["f.type != $type"];
const criteria: Record<string, any> = { $type: "Folder" };
if(query && query.owner !== undefined)
{
where.push("owner = $owner");
criteria["$owner"] = query.owner;
}
if(query && query.name !== undefined)
{
where.push("name = $name");
criteria["$name"] = query.name;
}
const db = useDatabase();
const content = db.query(`SELECT p.*, u.username, COUNT(f.path) as pages FROM explorer_projects p LEFT JOIN users u ON p.owner = u.id LEFT JOIN explorer_files f ON f.project = p.id WHERE ${where.join(" AND ")} GROUP BY p.id`).all(criteria) as ProjectSearch[];
if(content.length > 0)
{
return content;
}
setResponseStatus(e, 404);
});

View File

@ -1,20 +0,0 @@
import useDatabase from '~/composables/useDatabase';
export default defineEventHandler(async (e) => {
const project = getRouterParam(e, "projectId");
const where = ["id = $id"];
const criteria: Record<string, any> = { $id: project };
if (!!project) {
const db = useDatabase();
const content = db.query(`SELECT * FROM explorer_projects WHERE ${where.join(" and ")}`).get(criteria) as Project;
if (content) {
return content;
}
}
setResponseStatus(e, 404);
});

View File

@ -1,20 +0,0 @@
import useDatabase from '~/composables/useDatabase';
export default defineEventHandler(async (e) => {
const project = getRouterParam(e, "projectId");
const where = ["project = $project"];
const criteria: Record<string, any> = { $project: project };
if (!!project) {
const db = useDatabase();
const content = db.query(`SELECT * FROM explorer_projects WHERE ${where.join(" and ")}`).all(criteria) as Project[];
if (content.length > 0) {
return content;
}
}
setResponseStatus(e, 404);
});

View File

@ -1,20 +0,0 @@
import useDatabase from '~/composables/useDatabase';
export default defineEventHandler(async (e) => {
const project = getRouterParam(e, "projectId");
const where = ["project = $project"];
const criteria: Record<string, any> = { $project: project };
if (!!project) {
const db = useDatabase();
const content = db.query(`SELECT * FROM explorer_projects WHERE ${where.join(" and ")}`).all(criteria) as Project[];
if (content.length > 0) {
return content;
}
}
setResponseStatus(e, 404);
});

View File

@ -1,42 +0,0 @@
import useDatabase from '~/composables/useDatabase';
import type { Tag } from '~/types/api';
export default defineCachedEventHandler(async (e) => {
try
{
const project = getRouterParam(e, "projectId");
const tag = decodeURIComponent(getRouterParam(e, "tag") ?? '');
if(!project)
{
setResponseStatus(e, 404);
return;
}
if(!tag)
{
setResponseStatus(e, 404);
return;
}
const where = ["project = $project", "tag = $tag"];
const criteria: Record<string, any> = { $project: project, $tag: tag };
const db = useDatabase();
const content = db.query(`SELECT * FROM explorer_tags WHERE ${where.join(" and ")}`).get(criteria) as Tag;
if(content !== undefined)
{
return content;
}
setResponseStatus(e, 404);
}
catch(err)
{
console.error(err);
setResponseStatus(e, 500);
}
}, {
maxAge: 60*60*24,
getKey: (e) => `tag-${getRouterParam(e, "projectId")}-${getRouterParam(e, "tag")}`
});

View File

@ -6,7 +6,6 @@ export default defineEventHandler(async (e) => {
if (query.search) { if (query.search) {
const db = useDatabase(); const db = useDatabase();
const projects = db.query(`SELECT p.*, u.username, COUNT(f.path) as pages FROM explorer_projects p LEFT JOIN users u ON p.owner = u.id LEFT JOIN explorer_files f ON f.project = p.id WHERE name LIKE ?1 AND f.type != "Folder" GROUP BY p.id`).all(query.search) as ProjectSearch[];
const files = db.query(`SELECT f.*, u.username, count(c.path) as comments FROM explorer_files f LEFT JOIN users u ON f.owner = u.id LEFT JOIN explorer_comments c ON c.project = f.project AND c.path = f.path WHERE title LIKE ?1 AND private = 0 AND type != "Folder" GROUP BY f.project, f.path`).all(query.search) as FileSearch[]; const files = db.query(`SELECT f.*, u.username, count(c.path) as comments FROM explorer_files f LEFT JOIN users u ON f.owner = u.id LEFT JOIN explorer_comments c ON c.project = f.project AND c.path = f.path WHERE title LIKE ?1 AND private = 0 AND type != "Folder" GROUP BY f.project, f.path`).all(query.search) as FileSearch[];
const users = db.query(`SELECT id, username FROM users WHERE username LIKE ?1`).all(query.search) as UserSearch[]; const users = db.query(`SELECT id, username FROM users WHERE username LIKE ?1`).all(query.search) as UserSearch[];

View File

@ -1,4 +1,6 @@
import { eq, sql } from "drizzle-orm";
import useDatabase from "~/composables/useDatabase"; import useDatabase from "~/composables/useDatabase";
import { usersTable } from "~/db/schema";
import type { User } from "~/types/auth"; import type { User } from "~/types/auth";
export default defineEventHandler((e) => { export default defineEventHandler((e) => {
@ -12,5 +14,18 @@ export default defineEventHandler((e) => {
const db = useDatabase(); const db = useDatabase();
return db.query(`SELECT id, username, email, state, d.* FROM users u LEFT JOIN users_data d ON u.id = d.user_id WHERE u.id = ?1`).get(id) as User; const user = db.query.usersTable.findFirst({
columns: {
username: true,
},
with: {
data: true
},
where: eq(usersTable.id, sql.placeholder('id')),
}).prepare().get({ id });
return {
username: user?.username,
...user?.data
} as User
}); });

View File

@ -1,16 +0,0 @@
import useDatabase from "~/composables/useDatabase";
import type { ProjectSearch } from "~/types/api";
export default defineEventHandler((e) => {
const id = getRouterParam(e, 'id');
if(!id)
{
setResponseStatus(e, 400);
return;
}
const db = useDatabase();
return db.query(`SELECT p.*, count(f.path) as pages FROM explorer_projects p LEFT JOIN explorer_files f ON p.id = f.project WHERE p.owner = ?1`).all(id) as Omit<ProjectSearch, 'username'>[];
});

View File

@ -14,6 +14,7 @@ export default defineTask({
description: 'Synchronise the project 1 with Obsidian', description: 'Synchronise the project 1 with Obsidian',
}, },
async run(event) { async run(event) {
console.log('Task "sync" executed');
/* try { /* try {
const tree = await $fetch('https://git.peaceultime.com/api/v1/repos/peaceultime/system-aspect/git/trees/master', { const tree = await $fetch('https://git.peaceultime.com/api/v1/repos/peaceultime/system-aspect/git/trees/master', {
method: 'get', method: 'get',