Add insertion and deletion of tables for db sync, and user view
This commit is contained in:
parent
fa1a13d411
commit
e904f28b3b
|
|
@ -76,7 +76,7 @@ async function debounced()
|
|||
<div class="cursor-pointer hover:bg-light-25 dark:hover:bg-dark-25 px-4 py-1 " v-for="result of results.users" :key="result.id"
|
||||
@mouseenter="(e) => (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');">
|
||||
<div class="">
|
||||
<Highlight class="text-lg" :text="result.username" :matched="input" />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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[];
|
||||
|
||||
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`);
|
||||
}
|
||||
})).immediate(schema);
|
||||
else
|
||||
{
|
||||
db.exec(table.sql);
|
||||
}
|
||||
}
|
||||
for(const table of oldTables)
|
||||
{
|
||||
db.exec(`DROP TABLE ${table.name}`);
|
||||
}
|
||||
})).immediate(schema, oldSchema);
|
||||
|
||||
db.exec(`PRAGMA foreign_keys = 1`);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,13 +2,8 @@
|
|||
<Head>
|
||||
<Title>Inconnu</Title>
|
||||
</Head>
|
||||
<div class="site-body-center-column">
|
||||
<div class="render-container">
|
||||
<div class="not-found-container">
|
||||
<div class="not-found-image"></div>
|
||||
<div class="not-found-title">Introuvable</div>
|
||||
<div class="not-found-description">Cette page n'existe pas</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="h-100 w-100 flex flex-1 flex-col justify-center items-center">
|
||||
<div class="text-3xl font-extralight tracking-wide text-light-60 dark:text-dark-60">Introuvable</div>
|
||||
<div class="text-lg text-light-60 dark:text-dark-60">Cette page n'existe pas</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,6 +1,31 @@
|
|||
<script setup lang="ts">
|
||||
const route = useRoute();
|
||||
const { data: user } = useFetch(`/api/users/${route.params.id}`);
|
||||
const { data: projects } = useFetch(`/api/users/${route.params.id}/projects`);
|
||||
const { data: comments } = useFetch(`/api/users/${route.params.id}/comments`);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Head>
|
||||
<Title>Inconnu</Title>
|
||||
</Head>
|
||||
<div>TODO :)</div>
|
||||
<div v-if="user" class="border border-light-35 dark:border-dark-35 p-4 flex">
|
||||
<div>
|
||||
<picture :width=128 :height=128 class="flex" >
|
||||
<source :src="`/users/${user?.id}/normal.jpg`" :width=128 :height=128 />
|
||||
<Icon :icon="`users/unknown`" :width=128 :height=128 ></Icon>
|
||||
</picture>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-xl font-semibold">{{ user?.username }}</span>
|
||||
<span>Inscrit depuis le {{ format(new Date(user.signin_timestamp), 'dd/MM/yyyy') }}</span>
|
||||
<br/>
|
||||
<span>A créé {{ projects?.length ?? 0 }} projet(s)</span>
|
||||
<span>A créé {{ comments?.length ?? 0 }} commentaire(s)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="h-100 w-100 flex flex-1 flex-col justify-center items-center">
|
||||
<div class="text-3xl font-extralight tracking-wide text-light-60 dark:text-dark-60">Introuvable</div>
|
||||
<div class="text-lg text-light-60 dark:text-dark-60">Cette page n'existe pas</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -62,13 +62,13 @@ export default defineEventHandler(async (e): Promise<Return> => {
|
|||
{
|
||||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
});
|
||||
|
|
@ -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[];
|
||||
});
|
||||
|
|
@ -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[];
|
||||
});
|
||||
|
|
@ -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
|
||||
|
|
@ -24,9 +26,13 @@ export default defineNitroPlugin(() => {
|
|||
});
|
||||
sessionHooks.hook('clear', async (session, event) => {
|
||||
if(session.id && session.user)
|
||||
{
|
||||
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) { }
|
||||
}
|
||||
});
|
||||
});
|
||||
BIN
template.sqlite
BIN
template.sqlite
Binary file not shown.
|
|
@ -28,7 +28,7 @@ export interface UserRawData {
|
|||
}
|
||||
|
||||
export interface UserExtendedData {
|
||||
|
||||
signin_timestamp: number;
|
||||
}
|
||||
|
||||
export type User = UserRawData & UserExtendedData;
|
||||
|
|
|
|||
|
|
@ -6,3 +6,30 @@ 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;
|
||||
}
|
||||
Loading…
Reference in New Issue