initial commit

This commit is contained in:
Karlsson
2025-11-21 15:11:33 +01:00
commit c16fd804c0
62 changed files with 9335 additions and 0 deletions

44
src/lib/server/auth.ts Normal file
View File

@ -0,0 +1,44 @@
import { Lucia } from 'lucia';
import { dev } from '$app/environment';
import { DrizzlePostgreSQLAdapter } from '@lucia-auth/adapter-drizzle';
import { db } from './db';
import { sessions, users } from './db/schema';
import { Gitea } from 'arctic';
import { GITEA_BASE_URL, GITEA_CLIENT_ID, GITEA_CLIENT_SECRET } from '$env/static/private';
const adapter = new DrizzlePostgreSQLAdapter(db, sessions, users);
export const lucia = new Lucia(adapter, {
sessionCookie: {
attributes: {
secure: !dev
}
},
getUserAttributes: (attributes) => {
return {
username: attributes.username,
giteaId: attributes.giteaId,
avatarUrl: attributes.avatarUrl
};
}
});
declare module 'lucia' {
interface Register {
Lucia: typeof lucia;
DatabaseUserAttributes: DatabaseUserAttributes;
}
}
interface DatabaseUserAttributes {
username: string;
giteaId: number;
avatarUrl: string;
}
export const gitea = new Gitea(
GITEA_BASE_URL,
GITEA_CLIENT_ID,
GITEA_CLIENT_SECRET,
'http://localhost:5173/login/gitea/callback'
);

View File

@ -0,0 +1,27 @@
import { db } from '$lib/server/db';
import { comments } from '$lib/server/db/schema';
import { eq } from 'drizzle-orm';
export async function createComment(itemId: string, userId: string, text: string) {
return await db.insert(comments).values({
itemId,
userId,
text
}).returning();
}
export async function deleteComment(id: string) {
return await db.delete(comments)
.where(eq(comments.id, id))
.returning();
}
export async function getComments(itemId: string) {
return await db.query.comments.findMany({
where: eq(comments.itemId, itemId),
with: {
user: true
},
orderBy: (comments, { asc }) => [asc(comments.createdAt)]
});
}

View File

@ -0,0 +1,9 @@
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import { env } from '$env/dynamic/private';
import * as schema from './schema';
if (!env.DATABASE_URL) throw new Error('DATABASE_URL is not set');
const client = postgres(env.DATABASE_URL);
export const db = drizzle(client, { schema });

105
src/lib/server/db/schema.ts Normal file
View File

@ -0,0 +1,105 @@
import { pgTable, uuid, text, integer, jsonb, timestamp, foreignKey } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
export const folders = pgTable('folders', {
id: uuid('id').primaryKey().defaultRandom(),
name: text('name').notNull(),
parentId: uuid('parent_id'),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at').defaultNow().notNull()
}, (table) => {
return {
parentReference: foreignKey({
columns: [table.parentId],
foreignColumns: [table.id],
name: 'folders_parent_id_fkey'
})
};
});
export const categories = pgTable('categories', {
id: uuid('id').primaryKey().defaultRandom(),
name: text('name').notNull(),
defaultProperties: jsonb('default_properties').$type<string[]>().default([]).notNull(),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at').defaultNow().notNull()
});
export const items = pgTable('items', {
id: uuid('id').primaryKey().defaultRandom(),
folderId: uuid('folder_id').references(() => folders.id).notNull(),
categoryId: uuid('category_id').references(() => categories.id).notNull(),
name: text('name').notNull(),
count: integer('count').default(0).notNull(),
tags: jsonb('tags').$type<string[]>().default([]).notNull(),
properties: jsonb('properties').$type<Record<string, any>>().default({}).notNull(),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at').defaultNow().notNull()
});
export const users = pgTable('users', {
id: text('id').primaryKey(),
giteaId: integer('gitea_id').unique(),
username: text('username').notNull(),
avatarUrl: text('avatar_url')
});
export const sessions = pgTable('sessions', {
id: text('id').primaryKey(),
userId: text('user_id')
.notNull()
.references(() => users.id),
expiresAt: timestamp('expires_at', { withTimezone: true, mode: 'date' }).notNull()
});
export const reservations = pgTable('reservations', {
id: uuid('id').primaryKey().defaultRandom(),
itemId: uuid('item_id')
.notNull()
.references(() => items.id, { onDelete: 'cascade' }),
userId: text('user_id')
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
count: integer('count').notNull(),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at').defaultNow().notNull()
});
export const comments = pgTable('comments', {
id: uuid('id').primaryKey().defaultRandom(),
itemId: uuid('item_id')
.notNull()
.references(() => items.id, { onDelete: 'cascade' }),
userId: text('user_id')
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
text: text('text').notNull(),
createdAt: timestamp('created_at').defaultNow().notNull()
});
export const itemsRelations = relations(items, ({ many }) => ({
reservations: many(reservations),
comments: many(comments)
}));
export const reservationsRelations = relations(reservations, ({ one }) => ({
item: one(items, {
fields: [reservations.itemId],
references: [items.id]
}),
user: one(users, {
fields: [reservations.userId],
references: [users.id]
})
}));
export const commentsRelations = relations(comments, ({ one }) => ({
item: one(items, {
fields: [comments.itemId],
references: [items.id]
}),
user: one(users, {
fields: [comments.userId],
references: [users.id]
})
}));

View File

@ -0,0 +1,37 @@
import { db } from '$lib/server/db';
import { reservations } from '$lib/server/db/schema';
import { eq, and } from 'drizzle-orm';
export async function createReservation(itemId: string, userId: string, count: number) {
return await db.insert(reservations).values({
itemId,
userId,
count
}).returning();
}
export async function updateReservation(id: string, count: number) {
if (count <= 0) {
return await deleteReservation(id);
}
return await db.update(reservations)
.set({ count, updatedAt: new Date() })
.where(eq(reservations.id, id))
.returning();
}
export async function deleteReservation(id: string) {
return await db.delete(reservations)
.where(eq(reservations.id, id))
.returning();
}
export async function getReservations(itemId: string) {
return await db.query.reservations.findMany({
where: eq(reservations.itemId, itemId),
with: {
user: true // Assuming we want user details, need to check relations
},
orderBy: (reservations, { desc }) => [desc(reservations.createdAt)]
});
}