(e.target as HTMLElement).classList.add('is-selected')"
@mouseleave="(e) => (e.target as HTMLElement).classList.remove('is-selected')"
- @mousedown.prevent="navigateTo(`/user/${result.id}`); input = ''; emit('navigate');">
+ @mousedown.prevent="navigateTo(`/users/${result.id}`); input = ''; emit('navigate');">
diff --git a/db.sqlite b/db.sqlite
index 4200a9b..c73c06c 100644
Binary files a/db.sqlite and b/db.sqlite differ
diff --git a/modules/database.sync/module.ts b/modules/database.sync/module.ts
index 24d6799..8989b14 100644
--- a/modules/database.sync/module.ts
+++ b/modules/database.sync/module.ts
@@ -26,22 +26,41 @@ export default defineNuxtModule({
const db = new Database(nuxt.options.runtimeConfig.dbFile);
db.exec(`PRAGMA foreign_keys = 0`);
+ const oldSchema = db.query(`SELECT * FROM sqlite_schema WHERE type = 'table'`).all() as Schema[];
const structure = db.query(`SELECT * FROM pragma_table_info(?1)`);
- (db.transaction((tables: Schema[]) => {
+ (db.transaction((tables: Schema[], oldTables: Schema[]) => {
for(const table of tables)
{
+ const oldIdx = oldTables.findIndex(e => e.name === table.name);
+
if(table.name === 'sqlite_sequence')
+ {
+ oldTables.splice(oldIdx, 1);
continue;
+ }
const columns = structure.all(table.name) as Structure[];
- db.exec(`ALTER TABLE ${table.name} RENAME TO ${table.name}_old`);
- db.exec(table.sql);
- db.exec(`INSERT INTO ${table.name} (${columns.map(e => `"${e.name}"`).join(', ')}) SELECT * FROM ${table.name}_old`);
- db.exec(`DROP TABLE ${table.name}_old`);
+ if(oldIdx !== -1)
+ {
+ oldTables.splice(oldIdx, 1);
+
+ db.exec(`ALTER TABLE ${table.name} RENAME TO ${table.name}_old`);
+ db.exec(table.sql);
+ db.exec(`INSERT INTO ${table.name} (${columns.map(e => `"${e.name}"`).join(', ')}) SELECT * FROM ${table.name}_old`);
+ db.exec(`DROP TABLE ${table.name}_old`);
+ }
+ else
+ {
+ db.exec(table.sql);
+ }
}
- })).immediate(schema);
+ for(const table of oldTables)
+ {
+ db.exec(`DROP TABLE ${table.name}`);
+ }
+ })).immediate(schema, oldSchema);
db.exec(`PRAGMA foreign_keys = 1`);
diff --git a/pages/[...slug].vue b/pages/[...slug].vue
index ee7f12f..09c7c43 100644
--- a/pages/[...slug].vue
+++ b/pages/[...slug].vue
@@ -2,13 +2,8 @@
-
-
-
-
Introuvable
-
Cette page n'existe pas
-
-
+
+
+
Cette page n'existe pas
\ No newline at end of file
diff --git a/pages/users/[id].vue b/pages/users/[id].vue
index e7024c0..7180fc9 100644
--- a/pages/users/[id].vue
+++ b/pages/users/[id].vue
@@ -1,6 +1,31 @@
+
+
Inconnu
- TODO :)
+
+
+
+ {{ user?.username }}
+ Inscrit depuis le {{ format(new Date(user.signin_timestamp), 'dd/MM/yyyy') }}
+
+ A créé {{ projects?.length ?? 0 }} projet(s)
+ A créé {{ comments?.length ?? 0 }} commentaire(s)
+
+
+
+
+
Cette page n'existe pas
+
\ No newline at end of file
diff --git a/server/api/auth/register.post.ts b/server/api/auth/register.post.ts
index bf3a59f..c173807 100644
--- a/server/api/auth/register.post.ts
+++ b/server/api/auth/register.post.ts
@@ -62,13 +62,13 @@ export default defineEventHandler(async (e): Promise
=> {
{
const hash = await Bun.password.hash(body.data.password);
const registration = db.query(`INSERT INTO users(username, email, hash, state) VALUES(?1, ?2, ?3, 0)`);
- registration.get(body.data.username, body.data.email, hash) as any;
+ registration.run(body.data.username, body.data.email, hash);
const userIdQuery = db.query(`SELECT id FROM users WHERE username = ?1`);
const id = (userIdQuery.get(body.data.username) as any).id;
- const registeringData = db.query(`INSERT INTO users_data(user_id) VALUES(?1)`);
- registeringData.get(id);
+ const registeringData = db.query(`INSERT INTO users_data(user_id, signin_timestamp) VALUES(?1, ?2)`);
+ registeringData.run(id, Date.now());
logSession(e, await setUserSession(e, { user: { id: id, username: body.data.username, email: body.data.email, state: 0 } }) as UserSessionRequired);
diff --git a/server/api/users/[id].get.ts b/server/api/users/[id].get.ts
index d45318d..1e65580 100644
--- a/server/api/users/[id].get.ts
+++ b/server/api/users/[id].get.ts
@@ -12,5 +12,5 @@ export default defineEventHandler((e) => {
const db = useDatabase();
- return db.query(`SELECT id, usernamme, email, state FROM users WHERE id = ?1`).get(id) as User;
+ 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;
});
\ No newline at end of file
diff --git a/server/api/users/[id]/comments.get.ts b/server/api/users/[id]/comments.get.ts
new file mode 100644
index 0000000..db50495
--- /dev/null
+++ b/server/api/users/[id]/comments.get.ts
@@ -0,0 +1,16 @@
+import useDatabase from "~/composables/useDatabase";
+import type { Comment } from "~/types/auth";
+
+export default defineEventHandler((e) => {
+ const id = getRouterParam(e, 'id');
+
+ if(!id)
+ {
+ setResponseStatus(e, 400);
+ return;
+ }
+
+ const db = useDatabase();
+
+ return db.query(`SELECT * FROM explorer_comments WHERE user_id = ?1`).all(id) as Comment[];
+});
\ No newline at end of file
diff --git a/server/api/users/[id]/projects.get.ts b/server/api/users/[id]/projects.get.ts
new file mode 100644
index 0000000..b96dff4
--- /dev/null
+++ b/server/api/users/[id]/projects.get.ts
@@ -0,0 +1,16 @@
+import useDatabase from "~/composables/useDatabase";
+import type { Project } 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 * FROM explorer_projects WHERE owner = ?1`).all(id) as Project[];
+});
\ No newline at end of file
diff --git a/server/plugins/session.ts b/server/plugins/session.ts
index 8701e58..0fb0e4c 100644
--- a/server/plugins/session.ts
+++ b/server/plugins/session.ts
@@ -11,10 +11,12 @@ export default defineNitroPlugin(() => {
if(!result)
{
+ clearUserSession(event);
throw createError({ statusCode: 401, message: 'Unauthorized' });
}
else if(result && result.lastRefresh && result.lastRefresh < Date.now() - monthAsMs)
{
+ clearUserSession(event);
throw createError({ statusCode: 401, message: 'Session has expired' });
}
else
@@ -25,8 +27,12 @@ export default defineNitroPlugin(() => {
sessionHooks.hook('clear', async (session, event) => {
if(session.id && session.user)
{
- const query = db.prepare('DELETE FROM user_sessions WHERE id = ?1 AND user_id = ?2');
- query.run(session.id, session.user.id);
+ try
+ {
+ const query = db.prepare('DELETE FROM user_sessions WHERE id = ?1 AND user_id = ?2');
+ query.run(session.id, session.user.id);
+ }
+ catch(e) { }
}
});
});
\ No newline at end of file
diff --git a/template.sqlite b/template.sqlite
index 381db22..903b355 100644
Binary files a/template.sqlite and b/template.sqlite differ
diff --git a/types/auth.d.ts b/types/auth.d.ts
index f2a8be5..0010eb9 100644
--- a/types/auth.d.ts
+++ b/types/auth.d.ts
@@ -28,7 +28,7 @@ export interface UserRawData {
}
export interface UserExtendedData {
-
+ signin_timestamp: number;
}
export type User = UserRawData & UserExtendedData;
diff --git a/utils/utils.ts b/utils/utils.ts
index 8a5a4d8..44a45a7 100644
--- a/utils/utils.ts
+++ b/utils/utils.ts
@@ -5,4 +5,31 @@ export function unifySlug(slug: string | string[]): string
export function parseId(id: string | undefined): string |undefined
{
return id?.normalize('NFD')?.replace(/[\u0300-\u036f]/g, '')?.replace(/^\d\. */g, '')?.replace(/\s/g, "-")?.replace(/%/g, "-percent")?.replace(/\?/g, "-q")?.toLowerCase();
+}
+export function padLeft(text: string, pad: string, length: number): string
+{
+ return text.concat(pad.repeat(length - text.length));
+}
+export function padRight(text: string, pad: string, length: number): string
+{
+ return pad.repeat(length - text.length).concat(text);
+}
+export function format(date: Date, template: string): string
+{
+ const transforms = {
+ "yyyy": (date: Date) => date.getUTCFullYear().toString(),
+ "MM": (date: Date) => padRight((date.getUTCMonth() + 1).toString(), '0', 2),
+ "dd": (date: Date) => padRight(date.getUTCDate().toString(), '0', 2),
+ "mm": (date: Date) => padRight(date.getFullYear().toString(), '0', 2),
+ "HH": (date: Date) => padRight(date.getFullYear().toString(), '0', 2),
+ "ss": (date: Date) => padRight(date.getFullYear().toString(), '0', 2),
+ };
+ const keys = Object.keys(transforms);
+
+ for(const key of keys)
+ {
+ template = template.replaceAll(key, () => transforms[key](date));
+ }
+
+ return template;
}
\ No newline at end of file