Add permissions
This commit is contained in:
parent
a392841012
commit
41951d7603
|
|
@ -7,7 +7,8 @@ export default function useDatabase()
|
||||||
{
|
{
|
||||||
if(!instance)
|
if(!instance)
|
||||||
{
|
{
|
||||||
const sqlite = new Database(useRuntimeConfig().database);
|
const database = useRuntimeConfig().database;
|
||||||
|
const sqlite = new Database(database);
|
||||||
instance = drizzle({ client: sqlite, schema });
|
instance = drizzle({ client: sqlite, schema });
|
||||||
|
|
||||||
instance.run("PRAGMA journal_mode = WAL;");
|
instance.run("PRAGMA journal_mode = WAL;");
|
||||||
|
|
|
||||||
BIN
db.sqlite-shm
BIN
db.sqlite-shm
Binary file not shown.
BIN
db.sqlite-wal
BIN
db.sqlite-wal
Binary file not shown.
|
|
@ -26,10 +26,10 @@ export const userSessionsTable = sqliteTable("user_sessions", {
|
||||||
|
|
||||||
export const userPermissionsTable = sqliteTable("user_permissions", {
|
export const userPermissionsTable = sqliteTable("user_permissions", {
|
||||||
id: int().notNull().references(() => usersTable.id, { onDelete: 'cascade', onUpdate: 'cascade' }),
|
id: int().notNull().references(() => usersTable.id, { onDelete: 'cascade', onUpdate: 'cascade' }),
|
||||||
permissions: text().notNull(),
|
permission: text().notNull(),
|
||||||
}, (table): SQLiteTableExtraConfig => {
|
}, (table): SQLiteTableExtraConfig => {
|
||||||
return {
|
return {
|
||||||
pk: primaryKey({ columns: [table.id, table.permissions] }),
|
pk: primaryKey({ columns: [table.id, table.permission] }),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
PRAGMA foreign_keys=OFF;--> statement-breakpoint
|
||||||
|
CREATE TABLE `__new_user_permissions` (
|
||||||
|
`id` integer NOT NULL,
|
||||||
|
`permission` text NOT NULL,
|
||||||
|
PRIMARY KEY(`id`, `permission`),
|
||||||
|
FOREIGN KEY (`id`) REFERENCES `users`(`id`) ON UPDATE cascade ON DELETE cascade
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
INSERT INTO `__new_user_permissions`("id", "permission") SELECT "id", "permission" FROM `user_permissions`;--> statement-breakpoint
|
||||||
|
DROP TABLE `user_permissions`;--> statement-breakpoint
|
||||||
|
ALTER TABLE `__new_user_permissions` RENAME TO `user_permissions`;--> statement-breakpoint
|
||||||
|
PRAGMA foreign_keys=ON;
|
||||||
|
|
@ -0,0 +1,300 @@
|
||||||
|
{
|
||||||
|
"version": "6",
|
||||||
|
"dialect": "sqlite",
|
||||||
|
"id": "6da7ff20-0db8-4055-a353-bb0ea2fa5e0b",
|
||||||
|
"prevId": "854cab71-b937-4f4f-80b0-cbb09c7b5944",
|
||||||
|
"tables": {
|
||||||
|
"explorer_content": {
|
||||||
|
"name": "explorer_content",
|
||||||
|
"columns": {
|
||||||
|
"path": {
|
||||||
|
"name": "path",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"owner": {
|
||||||
|
"name": "owner",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"name": "title",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"name": "type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"name": "content",
|
||||||
|
"type": "blob",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"navigable": {
|
||||||
|
"name": "navigable",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"private": {
|
||||||
|
"name": "private",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"explorer_content_owner_users_id_fk": {
|
||||||
|
"name": "explorer_content_owner_users_id_fk",
|
||||||
|
"tableFrom": "explorer_content",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"owner"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "cascade"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"user_permissions": {
|
||||||
|
"name": "user_permissions",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"permission": {
|
||||||
|
"name": "permission",
|
||||||
|
"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_permission_pk": {
|
||||||
|
"columns": [
|
||||||
|
"id",
|
||||||
|
"permission"
|
||||||
|
],
|
||||||
|
"name": "user_permissions_id_permission_pk"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"user_sessions": {
|
||||||
|
"name": "user_sessions",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
"name": "timestamp",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"user_sessions_user_id_users_id_fk": {
|
||||||
|
"name": "user_sessions_user_id_users_id_fk",
|
||||||
|
"tableFrom": "user_sessions",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "cascade"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"user_sessions_id_user_id_pk": {
|
||||||
|
"columns": [
|
||||||
|
"id",
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"name": "user_sessions_id_user_id_pk"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"users_data": {
|
||||||
|
"name": "users_data",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"signin": {
|
||||||
|
"name": "signin",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"users_data_id_users_id_fk": {
|
||||||
|
"name": "users_data_id_users_id_fk",
|
||||||
|
"tableFrom": "users_data",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "cascade"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"name": "users",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": true
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"name": "username",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"hash": {
|
||||||
|
"name": "hash",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"name": "state",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"users_username_unique": {
|
||||||
|
"name": "users_username_unique",
|
||||||
|
"columns": [
|
||||||
|
"username"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
},
|
||||||
|
"users_email_unique": {
|
||||||
|
"name": "users_email_unique",
|
||||||
|
"columns": [
|
||||||
|
"email"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
},
|
||||||
|
"users_hash_unique": {
|
||||||
|
"name": "users_hash_unique",
|
||||||
|
"columns": [
|
||||||
|
"hash"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"views": {},
|
||||||
|
"enums": {},
|
||||||
|
"_meta": {
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {},
|
||||||
|
"columns": {
|
||||||
|
"\"user_permissions\".\"permissions\"": "\"user_permissions\".\"permission\""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"internal": {
|
||||||
|
"indexes": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -15,6 +15,13 @@
|
||||||
"when": 1730832678255,
|
"when": 1730832678255,
|
||||||
"tag": "0001_sticky_jack_flag",
|
"tag": "0001_sticky_jack_flag",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 2,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1730985155814,
|
||||||
|
"tag": "0002_messy_solo",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { relations } from "drizzle-orm/relations";
|
||||||
|
import { users, explorerContent, userSessions, usersData, userPermissions } 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),
|
||||||
|
userPermissions: many(userPermissions),
|
||||||
|
}));
|
||||||
|
|
||||||
|
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]
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const userPermissionsRelations = relations(userPermissions, ({one}) => ({
|
||||||
|
user: one(users, {
|
||||||
|
fields: [userPermissions.id],
|
||||||
|
references: [users.id]
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
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" } ),
|
||||||
|
signin: integer().notNull(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const users = sqliteTable("users", {
|
||||||
|
id: integer().primaryKey({ autoIncrement: true }).notNull(),
|
||||||
|
username: text().notNull(),
|
||||||
|
email: text().notNull(),
|
||||||
|
hash: text().notNull(),
|
||||||
|
state: integer().default(0).notNull(),
|
||||||
|
},
|
||||||
|
(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 userPermissions = sqliteTable("user_permissions", {
|
||||||
|
id: integer().notNull().references(() => users.id, { onDelete: "cascade", onUpdate: "cascade" } ),
|
||||||
|
permissions: text().notNull(),
|
||||||
|
},
|
||||||
|
(table) => {
|
||||||
|
return {
|
||||||
|
pk0: primaryKey({ columns: [table.id, table.permissions], name: "user_permissions_id_permissions_pk"})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const drizzleMigrations = sqliteTable("__drizzle_migrations", {
|
||||||
|
});
|
||||||
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
export default defineNuxtRouteMiddleware(async (to, from) => {
|
export default defineNuxtRouteMiddleware(async (to, from) => {
|
||||||
const { loggedIn, ready, fetch } = useUserSession();
|
const { loggedIn, fetch, user } = useUserSession();
|
||||||
const meta = to.meta;
|
const meta = to.meta;
|
||||||
|
|
||||||
if(!ready)
|
|
||||||
await fetch();
|
await fetch();
|
||||||
|
|
||||||
if(!!meta.guestsGoesTo && !loggedIn.value)
|
if(!!meta.guestsGoesTo && !loggedIn.value)
|
||||||
|
|
@ -11,12 +10,40 @@ export default defineNuxtRouteMiddleware(async (to, from) => {
|
||||||
}
|
}
|
||||||
else if(meta.requireAuth && !loggedIn.value)
|
else if(meta.requireAuth && !loggedIn.value)
|
||||||
{
|
{
|
||||||
return abortNavigation();
|
return abortNavigation({ statusCode: 401, message: 'Unauthorized', });
|
||||||
}
|
}
|
||||||
else if(!!meta.usersGoesTo && loggedIn.value)
|
else if(!!meta.usersGoesTo && loggedIn.value)
|
||||||
{
|
{
|
||||||
return navigateTo(meta.usersGoesTo);
|
return navigateTo(meta.usersGoesTo);
|
||||||
}
|
}
|
||||||
|
else if(!!meta.validState && (!loggedIn.value || (user.value?.state ?? 0) === 0))
|
||||||
|
{
|
||||||
|
return abortNavigation({ statusCode: 401, message: 'Unauthorized', });
|
||||||
|
}
|
||||||
|
else if(!!meta.rights)
|
||||||
|
{
|
||||||
|
if(!user.value)
|
||||||
|
{
|
||||||
|
return abortNavigation({ statusCode: 401, message: 'Unauthorized', });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
let valid = false;
|
||||||
|
for(let i = 0; i < meta.rights.length; i++)
|
||||||
|
{
|
||||||
|
const list = meta.rights[i].split(' ');
|
||||||
|
|
||||||
|
if(list.every(e => user.value.permissions.includes(e)))
|
||||||
|
{
|
||||||
|
valid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!valid)
|
||||||
|
return abortNavigation({ statusCode: 401, message: 'Unauthorized', });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
"@nuxtjs/tailwindcss": "^6.12.2",
|
"@nuxtjs/tailwindcss": "^6.12.2",
|
||||||
"@vueuse/nuxt": "^11.1.0",
|
"@vueuse/nuxt": "^11.1.0",
|
||||||
"drizzle-orm": "^0.35.3",
|
"drizzle-orm": "^0.35.3",
|
||||||
"nuxt": "^3.13.2",
|
"nuxt": "^3.14.159",
|
||||||
"nuxt-security": "^2.0.0",
|
"nuxt-security": "^2.0.0",
|
||||||
"radix-vue": "^1.9.8",
|
"radix-vue": "^1.9.8",
|
||||||
"vue": "latest",
|
"vue": "latest",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
definePageMeta({
|
||||||
|
rights: ['admin'],
|
||||||
|
})
|
||||||
const job = ref<string>('');
|
const job = ref<string>('');
|
||||||
|
|
||||||
|
const toaster = useToast();
|
||||||
const data = ref(), status = ref<'idle' | 'pending' | 'success' | 'error'>('idle'), success = ref(false), err = ref(false), error = ref();
|
const data = ref(), status = ref<'idle' | 'pending' | 'success' | 'error'>('idle'), success = ref(false), err = ref(false), error = ref();
|
||||||
async function fetch()
|
async function fetch()
|
||||||
{
|
{
|
||||||
|
|
@ -19,6 +23,8 @@ async function fetch()
|
||||||
error.value = null;
|
error.value = null;
|
||||||
err.value = false;
|
err.value = false;
|
||||||
success.value = true;
|
success.value = true;
|
||||||
|
|
||||||
|
toaster.add({ duration: 10000, content: data.value ?? 'Job executé avec succès', type: 'success', timer: true, });
|
||||||
}
|
}
|
||||||
catch(e)
|
catch(e)
|
||||||
{
|
{
|
||||||
|
|
@ -26,6 +32,8 @@ async function fetch()
|
||||||
error.value = e;
|
error.value = e;
|
||||||
err.value = true;
|
err.value = true;
|
||||||
success.value = false;
|
success.value = false;
|
||||||
|
|
||||||
|
toaster.add({ duration: 10000, content: error.value, type: 'error', timer: true, });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ let { user, clear } = useUserSession();
|
||||||
<Head>
|
<Head>
|
||||||
<Title>Mon profil</Title>
|
<Title>Mon profil</Title>
|
||||||
</Head>
|
</Head>
|
||||||
<div class="flex w-full items-start py-8 gap-6" v-if="user">
|
<div class="grid grid-cols-4 w-full items-start py-8 gap-6 content-start" v-if="user">
|
||||||
<div class="flex gap-4 min-w-1/3 max-w-2/3 border border-light-35 dark:border-dark-35 p-4">
|
<div class="flex gap-4 col-span-3 border border-light-35 dark:border-dark-35 p-4">
|
||||||
<Avatar icon="radix-icons:person" :src="`/users/${user?.id}.medium.jpg`" class="w-32 h-32" />
|
<Avatar icon="radix-icons:person" :src="`/users/${user?.id}.medium.jpg`" class="w-32 h-32" />
|
||||||
<div class="flex flex-col items-start">
|
<div class="flex flex-col items-start">
|
||||||
<ProseH5>{{ user.username }}</ProseH5>
|
<ProseH5>{{ user.username }}</ProseH5>
|
||||||
|
|
@ -24,5 +24,19 @@ let { user, clear } = useUserSession();
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<Button @click="async () => await clear()">Se deconnecter</Button>
|
<Button @click="async () => await clear()">Se deconnecter</Button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex">
|
||||||
|
<ProseTable class="!m-0">
|
||||||
|
<ProseThead>
|
||||||
|
<ProseTr>
|
||||||
|
<ProseTh>Permission</ProseTh>
|
||||||
|
</ProseTr>
|
||||||
|
</ProseThead>
|
||||||
|
<ProseTbody>
|
||||||
|
<ProseTr v-for="permission in user.permissions">
|
||||||
|
<ProseTd>{{ permission }}</ProseTd>
|
||||||
|
</ProseTr>
|
||||||
|
</ProseTbody>
|
||||||
|
</ProseTable>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -73,6 +73,7 @@ export default defineEventHandler(async (e): Promise<Return> => {
|
||||||
},
|
},
|
||||||
with: {
|
with: {
|
||||||
data: true,
|
data: true,
|
||||||
|
permission: true,
|
||||||
},
|
},
|
||||||
where: (table) => eq(table.id, sql.placeholder('id'))
|
where: (table) => eq(table.id, sql.placeholder('id'))
|
||||||
}).prepare().get({ id: id.id });
|
}).prepare().get({ id: id.id });
|
||||||
|
|
@ -89,6 +90,7 @@ export default defineEventHandler(async (e): Promise<Return> => {
|
||||||
email: user.email,
|
email: user.email,
|
||||||
username: user.username,
|
username: user.username,
|
||||||
state: user.state,
|
state: user.state,
|
||||||
|
permissions: user.permission.map(e => e.permission),
|
||||||
}
|
}
|
||||||
}) as UserSessionRequired);
|
}) as UserSessionRequired);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ export default defineEventHandler(async (e): Promise<Return> => {
|
||||||
|
|
||||||
db.insert(usersDataTable).values({ id: sql.placeholder('id') }).prepare().run({ id: id.id });
|
db.insert(usersDataTable).values({ id: sql.placeholder('id') }).prepare().run({ id: id.id });
|
||||||
|
|
||||||
logSession(e, await setUserSession(e, { user: { id: id.id, username: body.data.username, email: body.data.email, state: 0, signin: new Date() } }) as UserSessionRequired);
|
logSession(e, await setUserSession(e, { user: { id: id.id, username: body.data.username, email: body.data.email, state: 0, signin: new Date(), permissions: [] } }) as UserSessionRequired);
|
||||||
|
|
||||||
setResponseStatus(e, 201);
|
setResponseStatus(e, 201);
|
||||||
return { success: true, session };
|
return { success: true, session };
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import useDatabase from "~/composables/useDatabase";
|
import useDatabase from "~/composables/useDatabase";
|
||||||
import { userSessionsTable } from "~/db/schema";
|
import { userSessionsTable } from "~/db/schema";
|
||||||
import { eq, and, sql } from "drizzle-orm";
|
import { eq, and, sql } from "drizzle-orm";
|
||||||
|
import { refreshSessionFromDB } from "../utils/user";
|
||||||
|
|
||||||
const monthAsMs = 60 * 60 * 24 * 30 * 1000;
|
const monthAsMs = 60 * 60 * 24 * 30 * 1000;
|
||||||
|
|
||||||
|
|
@ -25,6 +26,7 @@ export default defineNitroPlugin(() => {
|
||||||
await db.update(userSessionsTable).set({
|
await db.update(userSessionsTable).set({
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
}).where(and(eq(userSessionsTable.id, sql.placeholder('id')), eq(userSessionsTable.user_id, sql.placeholder('user_id')))).prepare().run({ id: session.id, user_id: session.user.id });
|
}).where(and(eq(userSessionsTable.id, sql.placeholder('id')), eq(userSessionsTable.user_id, sql.placeholder('user_id')))).prepare().run({ id: session.id, user_id: session.user.id });
|
||||||
|
await refreshSessionFromDB(event, session.id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
sessionHooks.hook('clear', async (session, event) => {
|
sessionHooks.hook('clear', async (session, event) => {
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,43 @@ export function logSession(e: H3Event<EventRequestHandler>, session: UserSession
|
||||||
{
|
{
|
||||||
const db = useDatabase();
|
const db = useDatabase();
|
||||||
|
|
||||||
console.log("Logging session %s", session.id)
|
|
||||||
db.insert(userSessionsTable).values({ id: sql.placeholder('id'), user_id: sql.placeholder('user_id'), timestamp: sql.placeholder('timestamp') }).prepare().run({ id: session.id, user_id: session.user.id, timestamp: new Date() });
|
db.insert(userSessionsTable).values({ id: sql.placeholder('id'), user_id: sql.placeholder('user_id'), timestamp: sql.placeholder('timestamp') }).prepare().run({ id: session.id, user_id: session.user.id, timestamp: new Date() });
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
export async function refreshSessionFromDB(e: H3Event<EventRequestHandler>, sessionId: string): Promise<void>
|
||||||
|
{
|
||||||
|
const db = useDatabase();
|
||||||
|
|
||||||
|
const user = db.query.userSessionsTable.findFirst({
|
||||||
|
columns: {
|
||||||
|
id: false,
|
||||||
|
},
|
||||||
|
with: {
|
||||||
|
users: {
|
||||||
|
with: {
|
||||||
|
permission: true,
|
||||||
|
data: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
where: (table) => eq(table.id, sql.placeholder('id'))
|
||||||
|
}).prepare().get({ id: sessionId });
|
||||||
|
|
||||||
|
if(user)
|
||||||
|
{
|
||||||
|
await replaceUserSession(e, {
|
||||||
|
id: sessionId,
|
||||||
|
user: {
|
||||||
|
...user.users.data,
|
||||||
|
email: user.users.email,
|
||||||
|
username: user.users.username,
|
||||||
|
state: user.users.state,
|
||||||
|
permissions: user.users.permission.map(e => e.permission),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw createError({ statusCode: 401, message: 'Invalid session' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,8 @@ declare module 'vue-router'
|
||||||
requiresAuth?: boolean;
|
requiresAuth?: boolean;
|
||||||
guestsGoesTo?: string;
|
guestsGoesTo?: string;
|
||||||
usersGoesTo?: string;
|
usersGoesTo?: string;
|
||||||
|
rights?: string[];
|
||||||
|
validState?: boolean;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,7 +33,9 @@ export interface UserExtendedData {
|
||||||
signin: Date;
|
signin: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type User = UserRawData & UserExtendedData;
|
export type Permissions = { permissions: string[] };
|
||||||
|
|
||||||
|
export type User = UserRawData & UserExtendedData & Permissions;
|
||||||
|
|
||||||
export interface UserSession {
|
export interface UserSession {
|
||||||
user?: User;
|
user?: User;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue