mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
Moving drizzle into it's own DB folder and moving all the table types to separate files.
This commit is contained in:
parent
0b58b3ff8f
commit
a8eed0d86d
98 changed files with 5648 additions and 6076 deletions
|
|
@ -2,8 +2,8 @@ import 'dotenv/config';
|
|||
import { defineConfig } from 'drizzle-kit';
|
||||
|
||||
export default defineConfig({
|
||||
schema: './src/schema.ts',
|
||||
out: './drizzle',
|
||||
schema: './src/db/schema/index.ts',
|
||||
out: './src/db/migrations',
|
||||
driver: 'pg',
|
||||
dbCredentials: {
|
||||
host: process.env.DATABASE_HOST || 'localhost',
|
||||
|
|
@ -11,10 +11,10 @@ export default defineConfig({
|
|||
user: process.env.DATABASE_USER,
|
||||
password: process.env.DATABASE_PASSWORD,
|
||||
database: process.env.DATABASE || 'boredgame',
|
||||
ssl: process.env.DATABASE_HOST !== 'localhost'
|
||||
ssl: process.env.DATABASE_HOST !== 'localhost',
|
||||
},
|
||||
// Print all statements
|
||||
verbose: true,
|
||||
// Always as for confirmation
|
||||
strict: true
|
||||
strict: true,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@
|
|||
"format": "prettier --plugin-search-dir . --write .",
|
||||
"site:update": "pnpm update -i -L",
|
||||
"generate": "drizzle-kit generate:pg",
|
||||
"migrate": "tsx ./src/migrate.ts",
|
||||
"seed": "tsx ./src/seed.ts",
|
||||
"migrate": "tsx src/db/migrate.ts",
|
||||
"seed": "tsx src/db/seed.ts",
|
||||
"push": "drizzle-kit push:pg"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
|||
9298
pnpm-lock.yaml
9298
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
|
@ -5,9 +5,11 @@ import {
|
|||
DATABASE_PASSWORD,
|
||||
DATABASE_HOST,
|
||||
DATABASE_DB,
|
||||
DATABASE_PORT
|
||||
DATABASE_PORT,
|
||||
DB_MIGRATING,
|
||||
DB_SEEDING,
|
||||
} from '$env/static/private';
|
||||
import * as schema from '../schema';
|
||||
import * as schema from './schema';
|
||||
|
||||
// create the connection
|
||||
const pool = new pg.Pool({
|
||||
|
|
@ -16,15 +18,15 @@ const pool = new pg.Pool({
|
|||
host: DATABASE_HOST,
|
||||
port: Number(DATABASE_PORT).valueOf(),
|
||||
database: DATABASE_DB,
|
||||
ssl: DATABASE_HOST !== 'localhost'
|
||||
ssl: DATABASE_HOST !== 'localhost',
|
||||
max: DB_MIGRATING || DB_SEEDING ? 1 : undefined,
|
||||
});
|
||||
|
||||
// user: DATABASE_USER,
|
||||
// password: DATABASE_PASSWORD,
|
||||
// host: DATABASE_HOST,
|
||||
// port: Number(DATABASE_PORT).valueOf(),
|
||||
// database: DATABASE_DB
|
||||
const db = drizzle(pool, {
|
||||
schema,
|
||||
logger: process.env.NODE_ENV === 'development',
|
||||
});
|
||||
|
||||
const db = drizzle(pool, { schema });
|
||||
export type db = typeof db;
|
||||
|
||||
export default db;
|
||||
24
src/db/schema/categories.ts
Normal file
24
src/db/schema/categories.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||
import categories_to_games from './categoriesToGames';
|
||||
|
||||
const categories = pgTable('categories', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
name: text('name'),
|
||||
slug: text('slug'),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export type Categories = InferSelectModel<typeof categories>;
|
||||
|
||||
export const categories_relations = relations(categories, ({ many }) => ({
|
||||
categories_to_games: many(categories_to_games),
|
||||
categoriesToExternalIds: many(categoriesToExternalIds),
|
||||
}));
|
||||
|
||||
export default categories;
|
||||
24
src/db/schema/categoriesToExternalIds.ts
Normal file
24
src/db/schema/categoriesToExternalIds.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { pgTable, primaryKey, uuid } from 'drizzle-orm/pg-core';
|
||||
import categories from './categories';
|
||||
import externalIds from './externalIds';
|
||||
|
||||
const categoriesToExternalIds = pgTable(
|
||||
'categories_to_external_ids',
|
||||
{
|
||||
categoryId: uuid('category_id')
|
||||
.notNull()
|
||||
.references(() => categories.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
externalId: uuid('external_id')
|
||||
.notNull()
|
||||
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
},
|
||||
(table) => {
|
||||
return {
|
||||
categoriesToExternalIdsPkey: primaryKey({
|
||||
columns: [table.categoryId, table.externalId],
|
||||
}),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export default categoriesToExternalIds;
|
||||
36
src/db/schema/categoriesToGames.ts
Normal file
36
src/db/schema/categoriesToGames.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import { pgTable, primaryKey, uuid } from 'drizzle-orm/pg-core';
|
||||
import { relations } from 'drizzle-orm';
|
||||
import categories from './categories';
|
||||
import games from './games';
|
||||
|
||||
const categories_to_games = pgTable(
|
||||
'categories_to_games',
|
||||
{
|
||||
category_id: uuid('category_id')
|
||||
.notNull()
|
||||
.references(() => categories.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
game_id: uuid('game_id')
|
||||
.notNull()
|
||||
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
},
|
||||
(table) => {
|
||||
return {
|
||||
categoriesToGamesPkey: primaryKey({
|
||||
columns: [table.category_id, table.game_id],
|
||||
}),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const categories_to_games_relations = relations(categories_to_games, ({ one }) => ({
|
||||
category: one(categories, {
|
||||
fields: [categories_to_games.category_id],
|
||||
references: [categories.id],
|
||||
}),
|
||||
game: one(games, {
|
||||
fields: [categories_to_games.game_id],
|
||||
references: [games.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export default categories_to_games;
|
||||
36
src/db/schema/collectionItems.ts
Normal file
36
src/db/schema/collectionItems.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import { integer, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||
import collections from './collections';
|
||||
import games from './games';
|
||||
|
||||
const collection_items = pgTable('collection_items', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
collection_id: uuid('collection_id')
|
||||
.notNull()
|
||||
.references(() => collections.id, { onDelete: 'cascade' }),
|
||||
game_id: uuid('game_id')
|
||||
.notNull()
|
||||
.references(() => games.id, { onDelete: 'cascade' }),
|
||||
times_played: integer('times_played').default(0),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export type CollectionItems = InferSelectModel<typeof collection_items>;
|
||||
|
||||
export const collection_item_relations = relations(collection_items, ({ one }) => ({
|
||||
collection: one(collections, {
|
||||
fields: [collection_items.collection_id],
|
||||
references: [collections.id],
|
||||
}),
|
||||
game: one(games, {
|
||||
fields: [collection_items.game_id],
|
||||
references: [games.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export default collection_items;
|
||||
28
src/db/schema/collections.ts
Normal file
28
src/db/schema/collections.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||
import users from './users';
|
||||
|
||||
const collections = pgTable('collections', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
user_id: uuid('user_id')
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: 'cascade' }),
|
||||
name: text('name').notNull().default('My Collection'),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export const collection_relations = relations(collections, ({ one }) => ({
|
||||
user: one(users, {
|
||||
fields: [collections.user_id],
|
||||
references: [users.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export type Collections = InferSelectModel<typeof collections>;
|
||||
|
||||
export default collections;
|
||||
32
src/db/schema/expansions.ts
Normal file
32
src/db/schema/expansions.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||
import games from './games';
|
||||
|
||||
export const expansions = pgTable('expansions', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
base_game_id: uuid('base_game_id')
|
||||
.notNull()
|
||||
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
game_id: uuid('game_id')
|
||||
.notNull()
|
||||
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export type Expansions = InferSelectModel<typeof expansions>;
|
||||
|
||||
export const expansion_relations = relations(expansions, ({ one }) => ({
|
||||
baseGame: one(games, {
|
||||
fields: [expansions.base_game_id],
|
||||
references: [games.id],
|
||||
}),
|
||||
game: one(games, {
|
||||
fields: [expansions.game_id],
|
||||
references: [games.id],
|
||||
}),
|
||||
}));
|
||||
25
src/db/schema/externalIds.ts
Normal file
25
src/db/schema/externalIds.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { pgEnum, pgTable, text, uuid } from 'drizzle-orm/pg-core';
|
||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||
import type { InferSelectModel } from 'drizzle-orm';
|
||||
|
||||
export const ExternalIdType = pgEnum('external_id_type', [
|
||||
'game',
|
||||
'category',
|
||||
'mechanic',
|
||||
'publisher',
|
||||
'designer',
|
||||
'artist',
|
||||
]);
|
||||
|
||||
const externalIds = pgTable('external_ids', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
type: ExternalIdType('type').notNull(),
|
||||
externalId: text('external_id').notNull(),
|
||||
});
|
||||
|
||||
export type ExternalIds = InferSelectModel<typeof externalIds>;
|
||||
|
||||
export default externalIds;
|
||||
57
src/db/schema/games.ts
Normal file
57
src/db/schema/games.ts
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import { index, integer, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||
import { tsvector } from '../../tsVector';
|
||||
import { type InferSelectModel, relations, sql } from 'drizzle-orm';
|
||||
import categoriesToGames from './categoriesToGames';
|
||||
import gamesToExternalIds from './gamesToExternalIds';
|
||||
import mechanicsToGames from './mechanicsToGames';
|
||||
import publishersToGames from './publishersToGames';
|
||||
|
||||
const games = pgTable(
|
||||
'games',
|
||||
{
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
name: text('name'),
|
||||
slug: text('slug'),
|
||||
description: text('description'),
|
||||
year_published: integer('year_published'),
|
||||
min_players: integer('min_players'),
|
||||
max_players: integer('max_players'),
|
||||
playtime: integer('playtime'),
|
||||
min_playtime: integer('min_playtime'),
|
||||
max_playtime: integer('max_playtime'),
|
||||
min_age: integer('min_age'),
|
||||
image_url: text('image_url'),
|
||||
thumb_url: text('thumb_url'),
|
||||
url: text('url'),
|
||||
text_searchable_index: tsvector('text_searchable_index'),
|
||||
last_sync_at: timestamp('last_sync_at', {
|
||||
withTimezone: true,
|
||||
mode: 'date',
|
||||
precision: 6,
|
||||
}),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
},
|
||||
(table) => {
|
||||
return {
|
||||
text_searchable_idx: index('text_searchable_idx')
|
||||
.on(table.text_searchable_index)
|
||||
.using(sql`'gin'`),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const gameRelations = relations(games, ({ many }) => ({
|
||||
categories_to_games: many(categoriesToGames),
|
||||
mechanics_to_games: many(mechanicsToGames),
|
||||
publishers_to_games: many(publishersToGames),
|
||||
gamesToExternalIds: many(gamesToExternalIds),
|
||||
}));
|
||||
|
||||
export type Games = InferSelectModel<typeof games>;
|
||||
|
||||
export default games;
|
||||
24
src/db/schema/gamesToExternalIds.ts
Normal file
24
src/db/schema/gamesToExternalIds.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { pgTable, primaryKey, uuid } from 'drizzle-orm/pg-core';
|
||||
import games from './games';
|
||||
import externalIds from './externalIds';
|
||||
|
||||
const gamesToExternalIds = pgTable(
|
||||
'games_to_external_ids',
|
||||
{
|
||||
gameId: uuid('game_id')
|
||||
.notNull()
|
||||
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
externalId: uuid('external_id')
|
||||
.notNull()
|
||||
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
},
|
||||
(table) => {
|
||||
return {
|
||||
gamesToExternalIdsPkey: primaryKey({
|
||||
columns: [table.gameId, table.externalId],
|
||||
}),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export default gamesToExternalIds;
|
||||
34
src/db/schema/index.ts
Normal file
34
src/db/schema/index.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
export { default as users, user_relations, type Users } from './users';
|
||||
export { default as recoveryCodes, type RecoveryCodes } from './recoveryCodes';
|
||||
export {
|
||||
default as password_reset_tokens,
|
||||
password_reset_token_relations,
|
||||
type PasswordResetTokens,
|
||||
} from './passwordResetTokens';
|
||||
export { default as sessions } from './sessions';
|
||||
export { default as roles, role_relations, type Roles } from './roles';
|
||||
export { default as userRoles, user_role_relations, type UserRoles } from './userRoles';
|
||||
export { default as collections, collection_relations, type Collections } from './collections';
|
||||
export {
|
||||
default as collectionItems,
|
||||
collection_item_relations,
|
||||
type CollectionItems,
|
||||
} from './collectionItems';
|
||||
export { default as wishlists, wishlists_relations, type Wishlists } from './wishlists';
|
||||
export {
|
||||
default as wishlistItems,
|
||||
wishlist_item_relations,
|
||||
type WishlistItems,
|
||||
} from './wishlistItems';
|
||||
export { default as externalIds, type ExternalIds, type ExternalIdType } from './externalIds';
|
||||
export { default as games, gameRelations, type Games } from './games';
|
||||
export { default as gamesToExternalIds } from './gamesToExternalIds';
|
||||
export { default as publishers, publishers_relations, type Publishers } from './publishers';
|
||||
export { default as publishersToGames, publishers_to_games_relations } from './publishersToGames';
|
||||
export { default as publishersToExternalIds } from './publishersToExternalIds';
|
||||
export { default as categories, categories_relations, type Categories } from './categories';
|
||||
export { default as categoriesToExternalIds } from './categoriesToExternalIds';
|
||||
export { default as categoriesToGames, categories_to_games_relations } from './categoriesToGames';
|
||||
export { default as mechanics, mechanics_relations, type Mechanics } from './mechanics';
|
||||
export { default as mechanicsToExternalIds } from './mechanicsToExternalIds';
|
||||
export { default as mechanicsToGames, mechanics_to_games_relations } from './mechanicsToGames';
|
||||
25
src/db/schema/mechanics.ts
Normal file
25
src/db/schema/mechanics.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||
import mechanicsToGames from './mechanicsToGames';
|
||||
import mechanicsToExternalIds from './mechanicsToExternalIds';
|
||||
|
||||
const mechanics = pgTable('mechanics', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
name: text('name'),
|
||||
slug: text('slug'),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export type Mechanics = InferSelectModel<typeof mechanics>;
|
||||
|
||||
export const mechanics_relations = relations(mechanics, ({ many }) => ({
|
||||
mechanics_to_games: many(mechanicsToGames),
|
||||
mechanicsToExternalIds: many(mechanicsToExternalIds),
|
||||
}));
|
||||
|
||||
export default mechanics;
|
||||
24
src/db/schema/mechanicsToExternalIds.ts
Normal file
24
src/db/schema/mechanicsToExternalIds.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { pgTable, primaryKey, uuid } from 'drizzle-orm/pg-core';
|
||||
import mechanics from './mechanics';
|
||||
import externalIds from './externalIds';
|
||||
|
||||
const mechanicsToExternalIds = pgTable(
|
||||
'mechanics_to_external_ids',
|
||||
{
|
||||
mechanicId: uuid('mechanic_id')
|
||||
.notNull()
|
||||
.references(() => mechanics.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
externalId: uuid('external_id')
|
||||
.notNull()
|
||||
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
},
|
||||
(table) => {
|
||||
return {
|
||||
mechanicsToExternalIdsPkey: primaryKey({
|
||||
columns: [table.mechanicId, table.externalId],
|
||||
}),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export default mechanicsToExternalIds;
|
||||
36
src/db/schema/mechanicsToGames.ts
Normal file
36
src/db/schema/mechanicsToGames.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import { pgTable, primaryKey, uuid } from 'drizzle-orm/pg-core';
|
||||
import { relations } from 'drizzle-orm';
|
||||
import mechanics from './mechanics';
|
||||
import games from './games';
|
||||
|
||||
const mechanics_to_games = pgTable(
|
||||
'mechanics_to_games',
|
||||
{
|
||||
mechanic_id: uuid('mechanic_id')
|
||||
.notNull()
|
||||
.references(() => mechanics.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
game_id: uuid('game_id')
|
||||
.notNull()
|
||||
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
},
|
||||
(table) => {
|
||||
return {
|
||||
mechanicsToGamesPkey: primaryKey({
|
||||
columns: [table.mechanic_id, table.game_id],
|
||||
}),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const mechanics_to_games_relations = relations(mechanics_to_games, ({ one }) => ({
|
||||
mechanic: one(mechanics, {
|
||||
fields: [mechanics_to_games.mechanic_id],
|
||||
references: [mechanics.id],
|
||||
}),
|
||||
game: one(games, {
|
||||
fields: [mechanics_to_games.game_id],
|
||||
references: [games.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export default mechanics_to_games;
|
||||
30
src/db/schema/passwordResetTokens.ts
Normal file
30
src/db/schema/passwordResetTokens.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||
import users from './users';
|
||||
|
||||
const password_reset_tokens = pgTable('password_reset_tokens', {
|
||||
id: text('id')
|
||||
.primaryKey()
|
||||
.$defaultFn(() => cuid2()),
|
||||
user_id: uuid('user_id')
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: 'cascade' }),
|
||||
expires_at: timestamp('expires_at', {
|
||||
withTimezone: true,
|
||||
mode: 'date',
|
||||
precision: 6,
|
||||
}),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export type PasswordResetTokens = InferSelectModel<typeof password_reset_tokens>;
|
||||
|
||||
export const password_reset_token_relations = relations(password_reset_tokens, ({ one }) => ({
|
||||
user: one(users, {
|
||||
fields: [password_reset_tokens.user_id],
|
||||
references: [users.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export default password_reset_tokens;
|
||||
25
src/db/schema/publishers.ts
Normal file
25
src/db/schema/publishers.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||
import publishers_to_games from './publishersToGames';
|
||||
import publishersToExternalIds from './publishersToExternalIds';
|
||||
|
||||
const publishers = pgTable('publishers', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
name: text('name'),
|
||||
slug: text('slug'),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export type Publishers = InferSelectModel<typeof publishers>;
|
||||
|
||||
export const publishers_relations = relations(publishers, ({ many }) => ({
|
||||
publishers_to_games: many(publishers_to_games),
|
||||
publishersToExternalIds: many(publishersToExternalIds),
|
||||
}));
|
||||
|
||||
export default publishers;
|
||||
24
src/db/schema/publishersToExternalIds.ts
Normal file
24
src/db/schema/publishersToExternalIds.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { pgTable, primaryKey, uuid } from 'drizzle-orm/pg-core';
|
||||
import publishers from './publishers';
|
||||
import externalIds from './externalIds';
|
||||
|
||||
const publishersToExternalIds = pgTable(
|
||||
'publishers_to_external_ids',
|
||||
{
|
||||
publisherId: uuid('publisher_id')
|
||||
.notNull()
|
||||
.references(() => publishers.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
externalId: uuid('external_id')
|
||||
.notNull()
|
||||
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
},
|
||||
(table) => {
|
||||
return {
|
||||
publishersToExternalIdsPkey: primaryKey({
|
||||
columns: [table.publisherId, table.externalId],
|
||||
}),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export default publishersToExternalIds;
|
||||
36
src/db/schema/publishersToGames.ts
Normal file
36
src/db/schema/publishersToGames.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import { pgTable, primaryKey, uuid } from 'drizzle-orm/pg-core';
|
||||
import { relations } from 'drizzle-orm';
|
||||
import publishers from './publishers';
|
||||
import games from './games';
|
||||
|
||||
const publishers_to_games = pgTable(
|
||||
'publishers_to_games',
|
||||
{
|
||||
publisher_id: uuid('publisher_id')
|
||||
.notNull()
|
||||
.references(() => publishers.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
game_id: uuid('game_id')
|
||||
.notNull()
|
||||
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
},
|
||||
(table) => {
|
||||
return {
|
||||
publishersToGamesPkey: primaryKey({
|
||||
columns: [table.publisher_id, table.game_id],
|
||||
}),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const publishers_to_games_relations = relations(publishers_to_games, ({ one }) => ({
|
||||
publisher: one(publishers, {
|
||||
fields: [publishers_to_games.publisher_id],
|
||||
references: [publishers.id],
|
||||
}),
|
||||
game: one(games, {
|
||||
fields: [publishers_to_games.game_id],
|
||||
references: [games.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export default publishers_to_games;
|
||||
18
src/db/schema/recoveryCodes.ts
Normal file
18
src/db/schema/recoveryCodes.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { boolean, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||
import type { InferSelectModel } from 'drizzle-orm';
|
||||
import users from './users';
|
||||
|
||||
const recovery_codes = pgTable('recovery_codes', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
userId: uuid('user_id')
|
||||
.notNull()
|
||||
.references(() => users.id),
|
||||
code: text('code').notNull(),
|
||||
used: boolean('used').default(false),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export type RecoveryCodes = InferSelectModel<typeof recovery_codes>;
|
||||
|
||||
export default recovery_codes;
|
||||
21
src/db/schema/roles.ts
Normal file
21
src/db/schema/roles.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { pgTable, text, uuid } from 'drizzle-orm/pg-core';
|
||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||
import user_roles from './userRoles';
|
||||
|
||||
const roles = pgTable('roles', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2())
|
||||
.notNull(),
|
||||
name: text('name').unique().notNull(),
|
||||
});
|
||||
|
||||
export type Roles = InferSelectModel<typeof roles>;
|
||||
|
||||
export const role_relations = relations(roles, ({ many }) => ({
|
||||
user_roles: many(user_roles),
|
||||
}));
|
||||
|
||||
export default roles;
|
||||
17
src/db/schema/sessions.ts
Normal file
17
src/db/schema/sessions.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||
import users from './users';
|
||||
|
||||
const sessions = pgTable('sessions', {
|
||||
id: text('id').primaryKey(),
|
||||
userId: uuid('user_id')
|
||||
.notNull()
|
||||
.references(() => users.id),
|
||||
expiresAt: timestamp('expires_at', {
|
||||
withTimezone: true,
|
||||
mode: 'date',
|
||||
}).notNull(),
|
||||
ipCountry: text('ip_country'),
|
||||
ipAddress: text('ip_address'),
|
||||
});
|
||||
|
||||
export default sessions;
|
||||
36
src/db/schema/userRoles.ts
Normal file
36
src/db/schema/userRoles.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import { boolean, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||
import users from './users';
|
||||
import roles from './roles';
|
||||
|
||||
const user_roles = pgTable('user_roles', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
user_id: uuid('user_id')
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: 'cascade' }),
|
||||
role_id: uuid('role_id')
|
||||
.notNull()
|
||||
.references(() => roles.id, { onDelete: 'cascade' }),
|
||||
primary: boolean('primary').default(false),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export const user_role_relations = relations(user_roles, ({ one }) => ({
|
||||
role: one(roles, {
|
||||
fields: [user_roles.role_id],
|
||||
references: [roles.id],
|
||||
}),
|
||||
user: one(users, {
|
||||
fields: [user_roles.user_id],
|
||||
references: [users.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export type UserRoles = InferSelectModel<typeof user_roles>;
|
||||
|
||||
export default user_roles;
|
||||
31
src/db/schema/users.ts
Normal file
31
src/db/schema/users.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import { boolean, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||
import user_roles from './userRoles';
|
||||
|
||||
const users = pgTable('users', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
username: text('username').unique(),
|
||||
hashed_password: text('hashed_password'),
|
||||
email: text('email').unique(),
|
||||
first_name: text('first_name'),
|
||||
last_name: text('last_name'),
|
||||
verified: boolean('verified').default(false),
|
||||
receive_email: boolean('receive_email').default(false),
|
||||
theme: text('theme').default('system'),
|
||||
two_factor_secret: text('two_factor_secret').default(''),
|
||||
two_factor_enabled: boolean('two_factor_enabled').default(false),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export const user_relations = relations(users, ({ many }) => ({
|
||||
user_roles: many(user_roles),
|
||||
}));
|
||||
|
||||
export type Users = InferSelectModel<typeof users>;
|
||||
|
||||
export default users;
|
||||
35
src/db/schema/wishlistItems.ts
Normal file
35
src/db/schema/wishlistItems.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||
import wishlists from './wishlists';
|
||||
import games from './games';
|
||||
|
||||
const wishlist_items = pgTable('wishlist_items', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
wishlist_id: uuid('wishlist_id')
|
||||
.notNull()
|
||||
.references(() => wishlists.id, { onDelete: 'cascade' }),
|
||||
game_id: uuid('game_id')
|
||||
.notNull()
|
||||
.references(() => games.id, { onDelete: 'cascade' }),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export type WishlistItems = InferSelectModel<typeof wishlist_items>;
|
||||
|
||||
export const wishlist_item_relations = relations(wishlist_items, ({ one }) => ({
|
||||
wishlist: one(wishlists, {
|
||||
fields: [wishlist_items.wishlist_id],
|
||||
references: [wishlists.id],
|
||||
}),
|
||||
game: one(games, {
|
||||
fields: [wishlist_items.game_id],
|
||||
references: [games.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export default wishlist_items;
|
||||
28
src/db/schema/wishlists.ts
Normal file
28
src/db/schema/wishlists.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||
import users from './users';
|
||||
|
||||
const wishlists = pgTable('wishlists', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
user_id: uuid('user_id')
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: 'cascade' }),
|
||||
name: text('name').notNull().default('My Wishlist'),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export type Wishlists = InferSelectModel<typeof wishlists>;
|
||||
|
||||
export const wishlists_relations = relations(wishlists, ({ one }) => ({
|
||||
user: one(users, {
|
||||
fields: [wishlists.user_id],
|
||||
references: [users.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export default wishlists;
|
||||
|
|
@ -2,7 +2,7 @@ import 'dotenv/config';
|
|||
import { drizzle } from 'drizzle-orm/node-postgres';
|
||||
import pg from 'pg';
|
||||
import * as schema from './schema';
|
||||
import {Argon2id} from "oslo/password";
|
||||
import { Argon2id } from 'oslo/password';
|
||||
|
||||
// create the connection
|
||||
const pool = new pg.Pool({
|
||||
|
|
@ -11,7 +11,7 @@ const pool = new pg.Pool({
|
|||
host: process.env.DATABASE_HOST,
|
||||
port: Number(process.env.DATABASE_PORT).valueOf(),
|
||||
database: process.env.DATABASE_DB,
|
||||
ssl: process.env.DATABASE_HOST !== 'localhost'
|
||||
ssl: process.env.DATABASE_HOST !== 'localhost',
|
||||
});
|
||||
|
||||
const db = drizzle(pool, { schema: schema });
|
||||
|
|
@ -40,31 +40,37 @@ console.log('Roles created.');
|
|||
console.log('Admin Role: ', adminRole);
|
||||
|
||||
const adminUser = await db
|
||||
.insert(schema.users)
|
||||
.values({
|
||||
username: `${process.env.ADMIN_USERNAME}`,
|
||||
email: '',
|
||||
hashed_password: await new Argon2id().hash(`${process.env.ADMIN_PASSWORD}`),
|
||||
first_name: 'Brad',
|
||||
last_name: 'S',
|
||||
verified: true
|
||||
})
|
||||
.returning()
|
||||
.onConflictDoNothing();
|
||||
.insert(schema.users)
|
||||
.values({
|
||||
username: `${process.env.ADMIN_USERNAME}`,
|
||||
email: '',
|
||||
hashed_password: await new Argon2id().hash(`${process.env.ADMIN_PASSWORD}`),
|
||||
first_name: 'Brad',
|
||||
last_name: 'S',
|
||||
verified: true,
|
||||
})
|
||||
.returning()
|
||||
.onConflictDoNothing();
|
||||
|
||||
console.log('Admin user created.', adminUser);
|
||||
|
||||
await db.insert(schema.user_roles).values({
|
||||
user_id: adminUser[0].id,
|
||||
role_id: adminRole[0].id
|
||||
}).onConflictDoNothing();
|
||||
await db
|
||||
.insert(schema.user_roles)
|
||||
.values({
|
||||
user_id: adminUser[0].id,
|
||||
role_id: adminRole[0].id,
|
||||
})
|
||||
.onConflictDoNothing();
|
||||
|
||||
console.log('Admin user given admin role.');
|
||||
|
||||
await db.insert(schema.user_roles).values({
|
||||
user_id: adminUser[0].id,
|
||||
role_id: userRole[0].id
|
||||
}).onConflictDoNothing();
|
||||
await db
|
||||
.insert(schema.user_roles)
|
||||
.values({
|
||||
user_id: adminUser[0].id,
|
||||
role_id: userRole[0].id,
|
||||
})
|
||||
.onConflictDoNothing();
|
||||
|
||||
console.log('Admin user given user role.');
|
||||
|
||||
44
src/env.ts
Normal file
44
src/env.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import { ZodError, z } from 'zod';
|
||||
|
||||
const stringBoolean = z.coerce
|
||||
.string()
|
||||
.transform((val) => {
|
||||
return val === 'true';
|
||||
})
|
||||
.default('false');
|
||||
|
||||
const EnvSchema = z.object({
|
||||
NODE_ENV: z.string().default('development'),
|
||||
DATABASE_USER: z.string(),
|
||||
DATABASE_PASSWORD: z.string(),
|
||||
DATABASE_HOST: z.string(),
|
||||
DATABASE_PORT: z.coerce.number(),
|
||||
DATABASE_DB: z.string(),
|
||||
DATABASE_URL: z.string(),
|
||||
PUBLIC_SITE_URL: z.string(),
|
||||
PUBLIC_UMAMI_DO_NOT_TRACK: z.string(),
|
||||
PUBLIC_UMAMI_ID: z.string(),
|
||||
PUBLIC_UMAMI_URL: z.string(),
|
||||
DB_MIGRATING: stringBoolean,
|
||||
DB_SEEDING: stringBoolean,
|
||||
});
|
||||
|
||||
export type EnvSchema = z.infer<typeof EnvSchema>;
|
||||
|
||||
try {
|
||||
EnvSchema.parse(process.env);
|
||||
} catch (error) {
|
||||
if (error instanceof ZodError) {
|
||||
let message = 'Missing required values in .env:\n';
|
||||
error.issues.forEach((issue) => {
|
||||
message += issue.path[0] + '\n';
|
||||
});
|
||||
const e = new Error(message);
|
||||
e.stack = '';
|
||||
throw e;
|
||||
} else {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
export default EnvSchema.parse(process.env);
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
import { enhance } from "$app/forms";
|
||||
import { MinusCircle, PlusCircle } from "lucide-svelte";
|
||||
import { Button } from '$components/ui/button';
|
||||
import type { CollectionItems, Wishlists } from "../../schema";
|
||||
import type { CollectionItems, Wishlists } from "$db/schema";
|
||||
|
||||
export let game_id: string;
|
||||
export let collection: CollectionItems;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import type { GameType, SavedGameType } from '$lib/types';
|
||||
import * as Card from "$lib/components/ui/card";
|
||||
import type { CollectionItems } from '../../schema';
|
||||
import type { CollectionItems } from '$db/schema';
|
||||
|
||||
export let game: GameType | CollectionItems;
|
||||
export let variant: 'default' | 'compact' = 'default';
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
import * as Avatar from '$components/ui/avatar';
|
||||
import { invalidateAll } from '$app/navigation';
|
||||
import Logo from '$components/logo.svelte';
|
||||
import type { Users } from '../../schema';
|
||||
import type { Users } from '$db/schema';
|
||||
|
||||
export let user: Users | null = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { generateIdFromEntropySize } from 'lucia';
|
||||
import { TimeSpan, createDate } from 'oslo';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import db from '$lib/drizzle';
|
||||
import { password_reset_tokens } from '../../schema';
|
||||
import db from '../../db';
|
||||
import { password_reset_tokens } from '$db/schema';
|
||||
|
||||
export async function createPasswordResetToken(userId: string): Promise<string> {
|
||||
// optionally invalidate all existing tokens
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
// lib/server/lucia.ts
|
||||
import { Lucia, TimeSpan } from 'lucia';
|
||||
import { DrizzlePostgreSQLAdapter } from '@lucia-auth/adapter-drizzle';
|
||||
import db from '$lib/drizzle';
|
||||
import { sessions, users } from '../../schema';
|
||||
import db from '../../db';
|
||||
import { sessions, users } from '$db/schema';
|
||||
|
||||
const adapter = new DrizzlePostgreSQLAdapter(db, sessions, users);
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ export const lucia = new Lucia(adapter, {
|
|||
getSessionAttributes: (attributes) => {
|
||||
return {
|
||||
ipCountry: attributes.ip_country,
|
||||
ipAddress: attributes.ip_address
|
||||
ipAddress: attributes.ip_address,
|
||||
};
|
||||
},
|
||||
getUserAttributes: (attributes) => {
|
||||
|
|
@ -28,7 +28,7 @@ export const lucia = new Lucia(adapter, {
|
|||
email: attributes.email,
|
||||
firstName: attributes.firstName,
|
||||
lastName: attributes.lastName,
|
||||
theme: attributes.theme
|
||||
theme: attributes.theme,
|
||||
};
|
||||
},
|
||||
sessionExpiresIn: new TimeSpan(30, 'd'), // 30 days
|
||||
|
|
@ -39,9 +39,9 @@ export const lucia = new Lucia(adapter, {
|
|||
// set to `true` when using HTTPS
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
sameSite: 'strict',
|
||||
domain
|
||||
}
|
||||
}
|
||||
domain,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
declare module 'lucia' {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { SvelteComponent } from 'svelte';
|
||||
import { collections } from '../schema';
|
||||
import { collections } from '$db/schema';
|
||||
|
||||
export type Message = { status: 'error' | 'success' | 'warning' | 'info'; text: string };
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,14 @@ import { error } from '@sveltejs/kit';
|
|||
import { eq } from 'drizzle-orm';
|
||||
import kebabCase from 'just-kebab-case';
|
||||
import { PUBLIC_SITE_URL } from '$env/static/public';
|
||||
import db from '$lib/drizzle';
|
||||
import { externalIds, type Mechanics, type Categories, categories, categoriesToExternalIds } from '../../../schema';
|
||||
import db from '../../../db';
|
||||
import {
|
||||
externalIds,
|
||||
type Mechanics,
|
||||
type Categories,
|
||||
categories,
|
||||
categoriesToExternalIds,
|
||||
} from '$db/schema';
|
||||
|
||||
export async function createCategory(locals: App.Locals, category: Categories, externalId: string) {
|
||||
if (!category || !externalId || externalId === '') {
|
||||
|
|
@ -12,7 +18,7 @@ export async function createCategory(locals: App.Locals, category: Categories, e
|
|||
|
||||
try {
|
||||
const dbExternalId = await db.query.externalIds.findFirst({
|
||||
where: eq(externalIds.externalId, externalId)
|
||||
where: eq(externalIds.externalId, externalId),
|
||||
});
|
||||
|
||||
if (dbExternalId) {
|
||||
|
|
@ -20,7 +26,7 @@ export async function createCategory(locals: App.Locals, category: Categories, e
|
|||
.select({
|
||||
id: categories.id,
|
||||
name: categories.name,
|
||||
slug: categories.slug
|
||||
slug: categories.slug,
|
||||
})
|
||||
.from(categories)
|
||||
.leftJoin(categoriesToExternalIds, eq(categoriesToExternalIds.externalId, externalId));
|
||||
|
|
@ -30,9 +36,9 @@ export async function createCategory(locals: App.Locals, category: Categories, e
|
|||
return new Response('Mechanic already exists', {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Location: `${PUBLIC_SITE_URL}/api/mechanic/${foundCategory[0].id}`
|
||||
Location: `${PUBLIC_SITE_URL}/api/mechanic/${foundCategory[0].id}`,
|
||||
},
|
||||
status: 409
|
||||
status: 409,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -44,25 +50,25 @@ export async function createCategory(locals: App.Locals, category: Categories, e
|
|||
.insert(categories)
|
||||
.values({
|
||||
name: category.name,
|
||||
slug: kebabCase(category.name ?? category.slug ?? '')
|
||||
slug: kebabCase(category.name ?? category.slug ?? ''),
|
||||
})
|
||||
.returning();
|
||||
const dbExternalIds = await transaction
|
||||
.insert(externalIds)
|
||||
.values({
|
||||
externalId,
|
||||
type: 'category'
|
||||
type: 'category',
|
||||
})
|
||||
.returning({ id: externalIds.id });
|
||||
await transaction.insert(categoriesToExternalIds).values({
|
||||
categoryId: dbCategory[0].id,
|
||||
externalId: dbExternalIds[0].id
|
||||
externalId: dbExternalIds[0].id,
|
||||
});
|
||||
});
|
||||
|
||||
if (dbCategory.length === 0) {
|
||||
return new Response('Could not create category', {
|
||||
status: 500
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { error } from '@sveltejs/kit';
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
import db from '$lib/drizzle';
|
||||
import { type Expansions, expansions } from '../../../schema';
|
||||
import db from '../../../db';
|
||||
import { type Expansions, expansions } from '$db/schema';
|
||||
import { PUBLIC_SITE_URL } from '$env/static/public';
|
||||
|
||||
export async function createExpansion(locals: App.Locals, expansion: Expansions) {
|
||||
|
|
@ -10,24 +10,26 @@ export async function createExpansion(locals: App.Locals, expansion: Expansions)
|
|||
}
|
||||
|
||||
try {
|
||||
const foundExpansion = await db.query.expansions
|
||||
.findFirst({
|
||||
where: and(eq(expansions.base_game_id, expansion.base_game_id), eq(expansions.game_id, expansion.game_id)),
|
||||
columns: {
|
||||
id: true,
|
||||
game_id: true,
|
||||
base_game_id: true
|
||||
}
|
||||
});
|
||||
const foundExpansion = await db.query.expansions.findFirst({
|
||||
where: and(
|
||||
eq(expansions.base_game_id, expansion.base_game_id),
|
||||
eq(expansions.game_id, expansion.game_id),
|
||||
),
|
||||
columns: {
|
||||
id: true,
|
||||
game_id: true,
|
||||
base_game_id: true,
|
||||
},
|
||||
});
|
||||
console.log('Expansion already exists', foundExpansion);
|
||||
if (foundExpansion) {
|
||||
console.log('Expansion Game ID', foundExpansion.game_id);
|
||||
return new Response('Expansion already exists', {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Location: `${PUBLIC_SITE_URL}/api/game/${foundExpansion.game_id}`
|
||||
Location: `${PUBLIC_SITE_URL}/api/game/${foundExpansion.game_id}`,
|
||||
},
|
||||
status: 409
|
||||
status: 409,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -42,7 +44,7 @@ export async function createExpansion(locals: App.Locals, expansion: Expansions)
|
|||
|
||||
if (dbExpansion.length === 0) {
|
||||
return new Response('Could not create expansion', {
|
||||
status: 500
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -175,4 +177,4 @@ export async function createExpansion(locals: App.Locals, expansion: Expansions)
|
|||
// console.error(e);
|
||||
// throw new Error('Something went wrong creating Expansion');
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import kebabCase from 'just-kebab-case';
|
||||
import db from '$lib/drizzle';
|
||||
import { externalIds, gamesToExternalIds, type Games, games } from '../../../schema';
|
||||
import db from '../../../db';
|
||||
import { externalIds, gamesToExternalIds, type Games, games } from '$db/schema';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import { PUBLIC_SITE_URL } from '$env/static/public';
|
||||
|
|
@ -12,12 +12,12 @@ export async function getGame(locals: App.Locals, id: string) {
|
|||
|
||||
try {
|
||||
return await db.query.games.findFirst({
|
||||
where: eq(games.id, id)
|
||||
where: eq(games.id, id),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return new Response('Could not get games', {
|
||||
status: 500
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ export async function createGame(locals: App.Locals, game: Games, externalId: st
|
|||
|
||||
try {
|
||||
const dbExternalId = await db.query.externalIds.findFirst({
|
||||
where: eq(externalIds.externalId, externalId)
|
||||
where: eq(externalIds.externalId, externalId),
|
||||
});
|
||||
|
||||
if (dbExternalId) {
|
||||
|
|
@ -37,7 +37,7 @@ export async function createGame(locals: App.Locals, game: Games, externalId: st
|
|||
.select({
|
||||
id: games.id,
|
||||
name: games.name,
|
||||
slug: games.slug
|
||||
slug: games.slug,
|
||||
})
|
||||
.from(games)
|
||||
.leftJoin(gamesToExternalIds, eq(gamesToExternalIds.externalId, externalId));
|
||||
|
|
@ -47,9 +47,9 @@ export async function createGame(locals: App.Locals, game: Games, externalId: st
|
|||
return new Response('Game already exists', {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Location: `${PUBLIC_SITE_URL}/api/game/${foundGame[0].id}`
|
||||
Location: `${PUBLIC_SITE_URL}/api/game/${foundGame[0].id}`,
|
||||
},
|
||||
status: 409
|
||||
status: 409,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -71,25 +71,25 @@ export async function createGame(locals: App.Locals, game: Games, externalId: st
|
|||
min_players: game.min_players,
|
||||
max_players: game.max_players,
|
||||
min_playtime: game.min_playtime,
|
||||
max_playtime: game.max_playtime
|
||||
max_playtime: game.max_playtime,
|
||||
})
|
||||
.returning();
|
||||
const dbExternalIds = await transaction
|
||||
.insert(externalIds)
|
||||
.values({
|
||||
externalId,
|
||||
type: 'game'
|
||||
type: 'game',
|
||||
})
|
||||
.returning({ id: externalIds.id });
|
||||
await transaction.insert(gamesToExternalIds).values({
|
||||
gameId: dbGames[0].id,
|
||||
externalId: dbExternalIds[0].id
|
||||
externalId: dbExternalIds[0].id,
|
||||
});
|
||||
});
|
||||
|
||||
if (dbGames.length === 0) {
|
||||
return new Response('Could not create game', {
|
||||
status: 500
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -103,7 +103,11 @@ export async function createGame(locals: App.Locals, game: Games, externalId: st
|
|||
}
|
||||
}
|
||||
|
||||
export async function createOrUpdateGameMinimal(locals: App.Locals, game: Games, externalId: string) {
|
||||
export async function createOrUpdateGameMinimal(
|
||||
locals: App.Locals,
|
||||
game: Games,
|
||||
externalId: string,
|
||||
) {
|
||||
if (!game || !externalId || externalId === '') {
|
||||
error(400, 'Invalid Request');
|
||||
}
|
||||
|
|
@ -128,7 +132,7 @@ export async function createOrUpdateGameMinimal(locals: App.Locals, game: Games,
|
|||
min_players: game.min_players,
|
||||
max_players: game.max_players,
|
||||
min_playtime: game.min_playtime,
|
||||
max_playtime: game.max_playtime
|
||||
max_playtime: game.max_playtime,
|
||||
})
|
||||
.onConflictDoUpdate({
|
||||
target: games.id,
|
||||
|
|
@ -144,27 +148,30 @@ export async function createOrUpdateGameMinimal(locals: App.Locals, game: Games,
|
|||
min_players: game.min_players,
|
||||
max_players: game.max_players,
|
||||
min_playtime: game.min_playtime,
|
||||
max_playtime: game.max_playtime
|
||||
}
|
||||
max_playtime: game.max_playtime,
|
||||
},
|
||||
})
|
||||
.returning();
|
||||
const dbExternalIds = await transaction
|
||||
.insert(externalIds)
|
||||
.values({
|
||||
externalId,
|
||||
type: 'game'
|
||||
type: 'game',
|
||||
})
|
||||
.onConflictDoNothing()
|
||||
.returning({ id: externalIds.id });
|
||||
await transaction.insert(gamesToExternalIds).values({
|
||||
gameId: dbGames[0].id,
|
||||
externalId: dbExternalIds[0].id
|
||||
}).onConflictDoNothing();
|
||||
await transaction
|
||||
.insert(gamesToExternalIds)
|
||||
.values({
|
||||
gameId: dbGames[0].id,
|
||||
externalId: dbExternalIds[0].id,
|
||||
})
|
||||
.onConflictDoNothing();
|
||||
});
|
||||
|
||||
if (dbGames.length === 0) {
|
||||
return new Response('Could not create game', {
|
||||
status: 500
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +193,7 @@ export async function createOrUpdateGame(locals: App.Locals, game: Games, extern
|
|||
try {
|
||||
const externalUrl = `https://boardgamegeek.com/boardgame/${externalId}`;
|
||||
const dbExternalId = await db.query.externalIds.findFirst({
|
||||
where: eq(externalIds.externalId, externalId)
|
||||
where: eq(externalIds.externalId, externalId),
|
||||
});
|
||||
|
||||
if (dbExternalId) {
|
||||
|
|
@ -194,7 +201,7 @@ export async function createOrUpdateGame(locals: App.Locals, game: Games, extern
|
|||
.select({
|
||||
id: games.id,
|
||||
name: games.name,
|
||||
slug: games.slug
|
||||
slug: games.slug,
|
||||
})
|
||||
.from(games)
|
||||
.leftJoin(gamesToExternalIds, eq(gamesToExternalIds.externalId, externalId));
|
||||
|
|
@ -204,9 +211,9 @@ export async function createOrUpdateGame(locals: App.Locals, game: Games, extern
|
|||
return new Response('Game already exists', {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Location: `${PUBLIC_SITE_URL}/api/game/${foundGame[0].id}`
|
||||
Location: `${PUBLIC_SITE_URL}/api/game/${foundGame[0].id}`,
|
||||
},
|
||||
status: 409
|
||||
status: 409,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -228,7 +235,7 @@ export async function createOrUpdateGame(locals: App.Locals, game: Games, extern
|
|||
min_players: game.min_players,
|
||||
max_players: game.max_players,
|
||||
min_playtime: game.min_playtime,
|
||||
max_playtime: game.max_playtime
|
||||
max_playtime: game.max_playtime,
|
||||
})
|
||||
.onConflictDoUpdate({
|
||||
target: games.id,
|
||||
|
|
@ -244,27 +251,30 @@ export async function createOrUpdateGame(locals: App.Locals, game: Games, extern
|
|||
min_players: game.min_players,
|
||||
max_players: game.max_players,
|
||||
min_playtime: game.min_playtime,
|
||||
max_playtime: game.max_playtime
|
||||
}
|
||||
max_playtime: game.max_playtime,
|
||||
},
|
||||
})
|
||||
.returning();
|
||||
const dbExternalIds = await transaction
|
||||
.insert(externalIds)
|
||||
.values({
|
||||
externalId,
|
||||
type: 'game'
|
||||
type: 'game',
|
||||
})
|
||||
.onConflictDoNothing()
|
||||
.returning({ id: externalIds.id });
|
||||
await transaction.insert(gamesToExternalIds).values({
|
||||
gameId: dbGames[0].id,
|
||||
externalId: dbExternalIds[0].id
|
||||
}).onConflictDoNothing();
|
||||
await transaction
|
||||
.insert(gamesToExternalIds)
|
||||
.values({
|
||||
gameId: dbGames[0].id,
|
||||
externalId: dbExternalIds[0].id,
|
||||
})
|
||||
.onConflictDoNothing();
|
||||
});
|
||||
|
||||
if (dbGames.length === 0) {
|
||||
return new Response('Could not create game', {
|
||||
status: 500
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -298,142 +308,142 @@ export async function updateGame(locals: App.Locals, game: Games, id: string) {
|
|||
min_players: game.min_players,
|
||||
max_players: game.max_players,
|
||||
min_playtime: game.min_playtime,
|
||||
max_playtime: game.max_playtime
|
||||
max_playtime: game.max_playtime,
|
||||
})
|
||||
.where(eq(games.id, id))
|
||||
.returning();
|
||||
return new Response(JSON.stringify(dbGame[0]), {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return new Response('Could not get publishers', {
|
||||
status: 500
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// console.log('Creating or updating game', JSON.stringify(game, null, 2));
|
||||
// const categoryIds = game.categories;
|
||||
// const mechanicIds = game.mechanics;
|
||||
// const publisherIds = game.publishers;
|
||||
// const designerIds = game.designers;
|
||||
// const artistIds = game.artists;
|
||||
// // const expansionIds = game.expansions;
|
||||
// const externalUrl = `https://boardgamegeek.com/boardgame/${game.external_id}`;
|
||||
// console.log('categoryIds', categoryIds);
|
||||
// console.log('mechanicIds', mechanicIds);
|
||||
// await db.transaction(async (transaction) => {
|
||||
// const dbGame = await db.transaction(async (transaction) => {
|
||||
// transaction.insert(games).values({
|
||||
// name: game.name,
|
||||
// slug: kebabCase(game.name || ''),
|
||||
// description: game.description,
|
||||
// external_id: game.external_id,
|
||||
// url: externalUrl,
|
||||
// thumb_url: game.thumb_url,
|
||||
// image_url: game.image_url,
|
||||
// min_age: game.min_age || 0,
|
||||
// min_players: game.min_players || 0,
|
||||
// max_players: game.max_players || 0,
|
||||
// min_playtime: game.min_playtime || 0,
|
||||
// max_playtime: game.max_playtime || 0,
|
||||
// year_published: game.year_published || 0,
|
||||
// last_sync_at: new Date(),
|
||||
// }).onConflictDoUpdate({
|
||||
// target: games.id, set: {
|
||||
// name: game.name,
|
||||
// slug: kebabCase(game.name),
|
||||
// description: game.description,
|
||||
// external_id: game.external_id,
|
||||
// url: externalUrl,
|
||||
// thumb_url: game.thumb_url,
|
||||
// image_url: game.image_url,
|
||||
// min_age: game.min_age || 0,
|
||||
// min_players: game.min_players || 0,
|
||||
// max_players: game.max_players || 0,
|
||||
// min_playtime: game.min_playtime || 0,
|
||||
// max_playtime: game.max_playtime || 0,
|
||||
// year_published: game.year_published || 0,
|
||||
// last_sync_at: new Date(),
|
||||
// }
|
||||
// }).returning();
|
||||
// });
|
||||
// // TODO: Connect to everything else
|
||||
// });
|
||||
// await db.insert(games).values({
|
||||
// include: {
|
||||
// mechanics: true,
|
||||
// publishers: true,
|
||||
// designers: true,
|
||||
// artists: true,
|
||||
// expansions: true
|
||||
// },
|
||||
// where: {
|
||||
// external_id: game.external_id
|
||||
// },
|
||||
// create: {
|
||||
// name: game.name,
|
||||
// slug: kebabCase(game.name),
|
||||
// description: game.description,
|
||||
// external_id: game.external_id,
|
||||
// url: externalUrl,
|
||||
// thumb_url: game.thumb_url,
|
||||
// image_url: game.image_url,
|
||||
// min_age: game.min_age || 0,
|
||||
// min_players: game.min_players || 0,
|
||||
// max_players: game.max_players || 0,
|
||||
// min_playtime: game.min_playtime || 0,
|
||||
// max_playtime: game.max_playtime || 0,
|
||||
// year_published: game.year_published || 0,
|
||||
// last_sync_at: new Date(),
|
||||
// categories: {
|
||||
// connect: categoryIds
|
||||
// },
|
||||
// mechanics: {
|
||||
// connect: mechanicIds
|
||||
// },
|
||||
// publishers: {
|
||||
// connect: publisherIds
|
||||
// },
|
||||
// designers: {
|
||||
// connect: designerIds
|
||||
// },
|
||||
// artists: {
|
||||
// connect: artistIds
|
||||
// }
|
||||
// },
|
||||
// update: {
|
||||
// name: game.name,
|
||||
// slug: kebabCase(game.name),
|
||||
// description: game.description,
|
||||
// external_id: game.external_id,
|
||||
// url: externalUrl,
|
||||
// thumb_url: game.thumb_url,
|
||||
// image_url: game.image_url,
|
||||
// min_age: game.min_age || 0,
|
||||
// min_players: game.min_players || 0,
|
||||
// max_players: game.max_players || 0,
|
||||
// min_playtime: game.min_playtime || 0,
|
||||
// max_playtime: game.max_playtime || 0,
|
||||
// year_published: game.year_published || 0,
|
||||
// last_sync_at: new Date(),
|
||||
// categories: {
|
||||
// connect: categoryIds
|
||||
// },
|
||||
// mechanics: {
|
||||
// connect: mechanicIds
|
||||
// },
|
||||
// publishers: {
|
||||
// connect: publisherIds
|
||||
// },
|
||||
// designers: {
|
||||
// connect: designerIds
|
||||
// },
|
||||
// artists: {
|
||||
// connect: artistIds
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// const categoryIds = game.categories;
|
||||
// const mechanicIds = game.mechanics;
|
||||
// const publisherIds = game.publishers;
|
||||
// const designerIds = game.designers;
|
||||
// const artistIds = game.artists;
|
||||
// // const expansionIds = game.expansions;
|
||||
// const externalUrl = `https://boardgamegeek.com/boardgame/${game.external_id}`;
|
||||
// console.log('categoryIds', categoryIds);
|
||||
// console.log('mechanicIds', mechanicIds);
|
||||
// await db.transaction(async (transaction) => {
|
||||
// const dbGame = await db.transaction(async (transaction) => {
|
||||
// transaction.insert(games).values({
|
||||
// name: game.name,
|
||||
// slug: kebabCase(game.name || ''),
|
||||
// description: game.description,
|
||||
// external_id: game.external_id,
|
||||
// url: externalUrl,
|
||||
// thumb_url: game.thumb_url,
|
||||
// image_url: game.image_url,
|
||||
// min_age: game.min_age || 0,
|
||||
// min_players: game.min_players || 0,
|
||||
// max_players: game.max_players || 0,
|
||||
// min_playtime: game.min_playtime || 0,
|
||||
// max_playtime: game.max_playtime || 0,
|
||||
// year_published: game.year_published || 0,
|
||||
// last_sync_at: new Date(),
|
||||
// }).onConflictDoUpdate({
|
||||
// target: games.id, set: {
|
||||
// name: game.name,
|
||||
// slug: kebabCase(game.name),
|
||||
// description: game.description,
|
||||
// external_id: game.external_id,
|
||||
// url: externalUrl,
|
||||
// thumb_url: game.thumb_url,
|
||||
// image_url: game.image_url,
|
||||
// min_age: game.min_age || 0,
|
||||
// min_players: game.min_players || 0,
|
||||
// max_players: game.max_players || 0,
|
||||
// min_playtime: game.min_playtime || 0,
|
||||
// max_playtime: game.max_playtime || 0,
|
||||
// year_published: game.year_published || 0,
|
||||
// last_sync_at: new Date(),
|
||||
// }
|
||||
// }).returning();
|
||||
// });
|
||||
// // TODO: Connect to everything else
|
||||
// });
|
||||
// await db.insert(games).values({
|
||||
// include: {
|
||||
// mechanics: true,
|
||||
// publishers: true,
|
||||
// designers: true,
|
||||
// artists: true,
|
||||
// expansions: true
|
||||
// },
|
||||
// where: {
|
||||
// external_id: game.external_id
|
||||
// },
|
||||
// create: {
|
||||
// name: game.name,
|
||||
// slug: kebabCase(game.name),
|
||||
// description: game.description,
|
||||
// external_id: game.external_id,
|
||||
// url: externalUrl,
|
||||
// thumb_url: game.thumb_url,
|
||||
// image_url: game.image_url,
|
||||
// min_age: game.min_age || 0,
|
||||
// min_players: game.min_players || 0,
|
||||
// max_players: game.max_players || 0,
|
||||
// min_playtime: game.min_playtime || 0,
|
||||
// max_playtime: game.max_playtime || 0,
|
||||
// year_published: game.year_published || 0,
|
||||
// last_sync_at: new Date(),
|
||||
// categories: {
|
||||
// connect: categoryIds
|
||||
// },
|
||||
// mechanics: {
|
||||
// connect: mechanicIds
|
||||
// },
|
||||
// publishers: {
|
||||
// connect: publisherIds
|
||||
// },
|
||||
// designers: {
|
||||
// connect: designerIds
|
||||
// },
|
||||
// artists: {
|
||||
// connect: artistIds
|
||||
// }
|
||||
// },
|
||||
// update: {
|
||||
// name: game.name,
|
||||
// slug: kebabCase(game.name),
|
||||
// description: game.description,
|
||||
// external_id: game.external_id,
|
||||
// url: externalUrl,
|
||||
// thumb_url: game.thumb_url,
|
||||
// image_url: game.image_url,
|
||||
// min_age: game.min_age || 0,
|
||||
// min_players: game.min_players || 0,
|
||||
// max_players: game.max_players || 0,
|
||||
// min_playtime: game.min_playtime || 0,
|
||||
// max_playtime: game.max_playtime || 0,
|
||||
// year_published: game.year_published || 0,
|
||||
// last_sync_at: new Date(),
|
||||
// categories: {
|
||||
// connect: categoryIds
|
||||
// },
|
||||
// mechanics: {
|
||||
// connect: mechanicIds
|
||||
// },
|
||||
// publishers: {
|
||||
// connect: publisherIds
|
||||
// },
|
||||
// designers: {
|
||||
// connect: designerIds
|
||||
// },
|
||||
// artists: {
|
||||
// connect: artistIds
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import kebabCase from 'just-kebab-case';
|
||||
import db from '$lib/drizzle';
|
||||
import { externalIds, mechanics, mechanicsToExternalIds, type Mechanics } from '../../../schema';
|
||||
import db from '../../../db';
|
||||
import { externalIds, mechanics, mechanicsToExternalIds, type Mechanics } from '$db/schema';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import { PUBLIC_SITE_URL } from '$env/static/public';
|
||||
|
|
@ -12,7 +12,7 @@ export async function createMechanic(locals: App.Locals, mechanic: Mechanics, ex
|
|||
|
||||
try {
|
||||
const dbExternalId = await db.query.externalIds.findFirst({
|
||||
where: eq(externalIds.externalId, externalId)
|
||||
where: eq(externalIds.externalId, externalId),
|
||||
});
|
||||
|
||||
if (dbExternalId) {
|
||||
|
|
@ -20,7 +20,7 @@ export async function createMechanic(locals: App.Locals, mechanic: Mechanics, ex
|
|||
.select({
|
||||
id: mechanics.id,
|
||||
name: mechanics.name,
|
||||
slug: mechanics.slug
|
||||
slug: mechanics.slug,
|
||||
})
|
||||
.from(mechanics)
|
||||
.leftJoin(mechanicsToExternalIds, eq(mechanicsToExternalIds.externalId, externalId));
|
||||
|
|
@ -30,9 +30,9 @@ export async function createMechanic(locals: App.Locals, mechanic: Mechanics, ex
|
|||
return new Response('Mechanic already exists', {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Location: `${PUBLIC_SITE_URL}/api/mechanic/${foundMechanic[0].id}`
|
||||
Location: `${PUBLIC_SITE_URL}/api/mechanic/${foundMechanic[0].id}`,
|
||||
},
|
||||
status: 409
|
||||
status: 409,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -44,25 +44,25 @@ export async function createMechanic(locals: App.Locals, mechanic: Mechanics, ex
|
|||
.insert(mechanics)
|
||||
.values({
|
||||
name: mechanic.name,
|
||||
slug: kebabCase(mechanic.name || mechanic.slug || '')
|
||||
slug: kebabCase(mechanic.name || mechanic.slug || ''),
|
||||
})
|
||||
.returning();
|
||||
const dbExternalIds = await transaction
|
||||
.insert(externalIds)
|
||||
.values({
|
||||
externalId,
|
||||
type: 'mechanic'
|
||||
type: 'mechanic',
|
||||
})
|
||||
.returning({ id: externalIds.id });
|
||||
await transaction.insert(mechanicsToExternalIds).values({
|
||||
mechanicId: dbMechanics[0].id,
|
||||
externalId: dbExternalIds[0].id
|
||||
externalId: dbExternalIds[0].id,
|
||||
});
|
||||
});
|
||||
|
||||
if (dbMechanics.length === 0) {
|
||||
return new Response('Could not create mechanic', {
|
||||
status: 500
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,8 @@
|
|||
import { error } from '@sveltejs/kit';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import kebabCase from 'just-kebab-case';
|
||||
import db from '$lib/drizzle';
|
||||
import {
|
||||
externalIds,
|
||||
publishersToExternalIds,
|
||||
type Publishers,
|
||||
publishers,
|
||||
} from '../../../schema';
|
||||
import db from '../../../db';
|
||||
import { externalIds, publishersToExternalIds, type Publishers, publishers } from '$db/schema';
|
||||
import { PUBLIC_SITE_URL } from '$env/static/public';
|
||||
|
||||
export async function getPublisher(locals: App.Locals, id: string) {
|
||||
|
|
@ -17,8 +12,8 @@ export async function getPublisher(locals: App.Locals, id: string) {
|
|||
}
|
||||
return new Response(JSON.stringify(publisher[0]), {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -32,19 +27,19 @@ export async function updatePublisher(locals: App.Locals, publisher: Publishers,
|
|||
.update(publishers)
|
||||
.set({
|
||||
name: publisher.name,
|
||||
slug: kebabCase(publisher.name || '')
|
||||
slug: kebabCase(publisher.name || ''),
|
||||
})
|
||||
.where(eq(publishers.id, id))
|
||||
.returning();
|
||||
return new Response(JSON.stringify(dbPublisher[0]), {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return new Response('Could not get publishers', {
|
||||
status: 500
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -52,7 +47,7 @@ export async function updatePublisher(locals: App.Locals, publisher: Publishers,
|
|||
export async function createPublisher(
|
||||
locals: App.Locals,
|
||||
publisher: Publishers,
|
||||
externalId: string
|
||||
externalId: string,
|
||||
) {
|
||||
if (!publisher || !externalId || externalId === '') {
|
||||
error(400, 'Invalid Request');
|
||||
|
|
@ -60,7 +55,7 @@ export async function createPublisher(
|
|||
|
||||
try {
|
||||
const dbExternalId = await db.query.externalIds.findFirst({
|
||||
where: eq(externalIds.externalId, externalId)
|
||||
where: eq(externalIds.externalId, externalId),
|
||||
});
|
||||
|
||||
if (dbExternalId) {
|
||||
|
|
@ -68,7 +63,7 @@ export async function createPublisher(
|
|||
.select({
|
||||
id: publishers.id,
|
||||
name: publishers.name,
|
||||
slug: publishers.slug
|
||||
slug: publishers.slug,
|
||||
})
|
||||
.from(publishers)
|
||||
.leftJoin(publishersToExternalIds, eq(publishersToExternalIds.externalId, externalId));
|
||||
|
|
@ -78,9 +73,9 @@ export async function createPublisher(
|
|||
return new Response('Publisher already exists', {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Location: `${PUBLIC_SITE_URL}/api/publisher/${foundPublisher[0].id}`
|
||||
Location: `${PUBLIC_SITE_URL}/api/publisher/${foundPublisher[0].id}`,
|
||||
},
|
||||
status: 409
|
||||
status: 409,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -92,25 +87,25 @@ export async function createPublisher(
|
|||
.insert(publishers)
|
||||
.values({
|
||||
name: publisher.name,
|
||||
slug: kebabCase(publisher.name || publisher.slug || '')
|
||||
slug: kebabCase(publisher.name || publisher.slug || ''),
|
||||
})
|
||||
.returning();
|
||||
const dbExternalIds = await transaction
|
||||
.insert(externalIds)
|
||||
.values({
|
||||
externalId,
|
||||
type: 'publisher'
|
||||
type: 'publisher',
|
||||
})
|
||||
.returning({ id: externalIds.id });
|
||||
await transaction.insert(publishersToExternalIds).values({
|
||||
publisherId: dbPublishers[0].id,
|
||||
externalId: dbExternalIds[0].id
|
||||
externalId: dbExternalIds[0].id,
|
||||
});
|
||||
});
|
||||
|
||||
if (dbPublishers.length === 0) {
|
||||
return new Response('Could not create publisher', {
|
||||
status: 500
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -122,4 +117,4 @@ export async function createPublisher(
|
|||
console.error(e);
|
||||
throw new Error('Something went wrong creating Publisher');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { GameType, SavedGameType } from '$lib/types';
|
||||
import kebabCase from 'just-kebab-case';
|
||||
import type { Games } from '../../schema';
|
||||
import type { Games } from '$db/schema';
|
||||
|
||||
export function convertToSavedGame(game: GameType | SavedGameType): SavedGameType {
|
||||
return {
|
||||
|
|
@ -9,7 +9,7 @@ export function convertToSavedGame(game: GameType | SavedGameType): SavedGameTyp
|
|||
thumb_url: game.thumb_url,
|
||||
players: game.players,
|
||||
playtime: game.playtime,
|
||||
searchTerms: `${game.name.toLowerCase()}`
|
||||
searchTerms: `${game.name.toLowerCase()}`,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ export function mapSavedGameToGame(game: SavedGameType): GameType {
|
|||
description: '',
|
||||
description_preview: '',
|
||||
players,
|
||||
playtime
|
||||
playtime,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -56,6 +56,6 @@ export function mapAPIGameToBoredGame(game: GameType): Games {
|
|||
min_playtime: game.min_playtime,
|
||||
max_playtime: game.max_playtime,
|
||||
min_age: game.min_age,
|
||||
description: game.description
|
||||
description: game.description,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { redirect, loadFlash } from 'sveltekit-flash-message/server';
|
||||
import { forbiddenMessage, notSignedInMessage } from '$lib/flashMessages';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import db from '$lib/drizzle';
|
||||
import { user_roles } from '../../../../schema';
|
||||
import db from '../../../../db';
|
||||
import { user_roles } from '$db/schema';
|
||||
|
||||
export const load = loadFlash(async (event) => {
|
||||
const { locals } = event;
|
||||
|
|
@ -16,10 +16,10 @@ export const load = loadFlash(async (event) => {
|
|||
with: {
|
||||
role: {
|
||||
columns: {
|
||||
name: true
|
||||
}
|
||||
}
|
||||
}
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const containsAdminRole = userRoles.some((user_role) => user_role?.role?.name === 'admin');
|
||||
|
|
|
|||
|
|
@ -1,23 +1,20 @@
|
|||
import { redirect } from "sveltekit-flash-message/server";
|
||||
import type { PageServerLoad } from "./$types";
|
||||
import { notSignedInMessage } from "$lib/flashMessages";
|
||||
import db from "$lib/drizzle";
|
||||
import { redirect } from 'sveltekit-flash-message/server';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { notSignedInMessage } from '$lib/flashMessages';
|
||||
import db from '../../../../../db';
|
||||
|
||||
export const load: PageServerLoad = async (event) => {
|
||||
|
||||
// TODO: Ensure admin user
|
||||
if (!event.locals.user) {
|
||||
redirect(302, '/login', notSignedInMessage, event);
|
||||
}
|
||||
|
||||
const users = await db.query
|
||||
.users
|
||||
.findMany({
|
||||
limit: 10,
|
||||
offset: 0
|
||||
});
|
||||
const users = await db.query.users.findMany({
|
||||
limit: 10,
|
||||
offset: 0,
|
||||
});
|
||||
|
||||
return {
|
||||
users
|
||||
users,
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import { and, eq, inArray, not } from 'drizzle-orm';
|
|||
import { redirect } from 'sveltekit-flash-message/server';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { forbiddenMessage, notSignedInMessage } from '$lib/flashMessages';
|
||||
import db from '$lib/drizzle';
|
||||
import { roles, user_roles, users } from '../../../../../../schema';
|
||||
import db from '../../../../../../db';
|
||||
import { roles, user_roles, users } from '$db/schema';
|
||||
|
||||
export const load: PageServerLoad = async (event) => {
|
||||
const { params } = event;
|
||||
|
|
@ -22,16 +22,16 @@ export const load: PageServerLoad = async (event) => {
|
|||
role: {
|
||||
columns: {
|
||||
name: true,
|
||||
cuid: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cuid: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const containsAdminRole = foundUser?.user_roles?.some(
|
||||
(user_role) => user_role?.role?.name === 'admin'
|
||||
(user_role) => user_role?.role?.name === 'admin',
|
||||
);
|
||||
if (!containsAdminRole) {
|
||||
console.log('Not an admin');
|
||||
|
|
@ -45,14 +45,14 @@ export const load: PageServerLoad = async (event) => {
|
|||
where: not(inArray(roles.cuid, currentRoleIds)),
|
||||
columns: {
|
||||
name: true,
|
||||
cuid: true
|
||||
}
|
||||
cuid: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
user: foundUser,
|
||||
availableRoles
|
||||
availableRoles,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -71,10 +71,10 @@ export const actions = {
|
|||
role: {
|
||||
columns: {
|
||||
name: true,
|
||||
cuid: true
|
||||
}
|
||||
}
|
||||
}
|
||||
cuid: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
console.log('userRoles', userRoles);
|
||||
|
|
@ -88,13 +88,13 @@ export const actions = {
|
|||
const data = await request.formData();
|
||||
const role = data.get('role');
|
||||
const dbRole = await db.query.roles.findFirst({
|
||||
where: eq(roles.cuid, role?.toString() ?? '')
|
||||
where: eq(roles.cuid, role?.toString() ?? ''),
|
||||
});
|
||||
console.log('dbRole', dbRole);
|
||||
if (dbRole) {
|
||||
await db.insert(user_roles).values({
|
||||
user_id: user.id,
|
||||
role_id: dbRole.id
|
||||
role_id: dbRole.id,
|
||||
});
|
||||
redirect({ type: 'success', message: `Successfully added role ${dbRole.name}!` }, event);
|
||||
} else {
|
||||
|
|
@ -114,10 +114,10 @@ export const actions = {
|
|||
role: {
|
||||
columns: {
|
||||
name: true,
|
||||
cuid: true
|
||||
}
|
||||
}
|
||||
}
|
||||
cuid: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const containsAdminRole = userRoles.some((user_role) => user_role?.role?.name === 'admin');
|
||||
|
|
@ -128,7 +128,7 @@ export const actions = {
|
|||
const data = await request.formData();
|
||||
const role = data.get('role');
|
||||
const dbRole = await db.query.roles.findFirst({
|
||||
where: eq(roles.cuid, role?.toString() ?? '')
|
||||
where: eq(roles.cuid, role?.toString() ?? ''),
|
||||
});
|
||||
console.log('dbRole', dbRole);
|
||||
if (dbRole) {
|
||||
|
|
@ -139,5 +139,5 @@ export const actions = {
|
|||
} else {
|
||||
redirect({ type: 'error', message: `Failed to remove role ${dbRole.name} !` }, event);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
import { Input } from "$lib/components/ui/input";
|
||||
import * as DropdownMenu from "$lib/components/ui/dropdown-menu";
|
||||
import DataTableCheckbox from "./user-table-checkbox.svelte";
|
||||
import type { Users } from '../../../../../schema';
|
||||
import type { Users } from '$db/schema';
|
||||
|
||||
export let users: Users[] = [];
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import { zod } from 'sveltekit-superforms/adapters';
|
|||
import { redirect } from 'sveltekit-flash-message/server';
|
||||
import { modifyListGameSchema, type ListGame } from '$lib/validations/zod-schemas';
|
||||
import { search_schema } from '$lib/zodValidation.js';
|
||||
import db from '$lib/drizzle';
|
||||
import { collection_items, collections, games } from '../../../../schema';
|
||||
import db from '../../../../db';
|
||||
import { collection_items, collections, games } from '$db/schema';
|
||||
import { notSignedInMessage } from '$lib/flashMessages';
|
||||
|
||||
export async function load(event) {
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ import { zod } from 'sveltekit-superforms/adapters';
|
|||
import { superValidate } from 'sveltekit-superforms/server';
|
||||
import { redirect } from 'sveltekit-flash-message/server';
|
||||
import { type ListGame, modifyListGameSchema } from '$lib/validations/zod-schemas';
|
||||
import db from '$lib/drizzle.js';
|
||||
import db from '../../../../../db';
|
||||
import { notSignedInMessage } from '$lib/flashMessages.js';
|
||||
import { collections, games, collection_items } from '../../../../../schema.js';
|
||||
import { collections, games, collection_items } from '$db/schema';
|
||||
import { search_schema } from '$lib/zodValidation';
|
||||
import type { UICollection } from '$lib/types';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { fail } from '@sveltejs/kit';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import db from '$lib/drizzle.js';
|
||||
import { wishlists } from '../../../../schema.js';
|
||||
import db from '../../../../db';
|
||||
import { wishlists } from '$db/schema';
|
||||
|
||||
export async function load({ locals }) {
|
||||
if (!locals.user) {
|
||||
|
|
@ -10,16 +10,16 @@ export async function load({ locals }) {
|
|||
|
||||
try {
|
||||
const userWishlists = await db.query.wishlists.findMany({
|
||||
where: eq(wishlists.user_id, locals.user.id)
|
||||
where: eq(wishlists.user_id, locals.user.id),
|
||||
});
|
||||
|
||||
return {
|
||||
wishlsits: userWishlists
|
||||
wishlsits: userWishlists,
|
||||
};
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
return {
|
||||
wishlists: []
|
||||
wishlists: [],
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { type Actions, fail, redirect } from "@sveltejs/kit";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { zod } from "sveltekit-superforms/adapters";
|
||||
import { type Actions, fail, redirect } from '@sveltejs/kit';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { zod } from 'sveltekit-superforms/adapters';
|
||||
import { superValidate } from 'sveltekit-superforms/server';
|
||||
import db from "$lib/drizzle.js";
|
||||
import { modifyListGameSchema } from "$lib/validations/zod-schemas";
|
||||
import { games, wishlist_items, wishlists } from "../../../../../schema.js";
|
||||
import db from '../../../../../db';
|
||||
import { modifyListGameSchema } from '$lib/validations/zod-schemas';
|
||||
import { games, wishlist_items, wishlists } from '$db/schema';
|
||||
|
||||
export async function load({ params, locals }) {
|
||||
const user = locals.user;
|
||||
|
|
@ -13,20 +13,22 @@ export async function load({ params, locals }) {
|
|||
}
|
||||
|
||||
try {
|
||||
const wishlist = await db.select({
|
||||
wishlistId: wishlists.id,
|
||||
wishlistItems: {
|
||||
id: wishlist_items.id,
|
||||
gameId: wishlist_items.game_id,
|
||||
gameName: games.name,
|
||||
gameThumbUrl: games.thumb_url
|
||||
},
|
||||
}).from(wishlists)
|
||||
.leftJoin(wishlist_items, eq(wishlists.id, wishlist_items.wishlist_id))
|
||||
.leftJoin(games, eq(games.id, wishlist_items.game_id))
|
||||
.where(eq(wishlists.id, params.id));
|
||||
const wishlist = await db
|
||||
.select({
|
||||
wishlistId: wishlists.id,
|
||||
wishlistItems: {
|
||||
id: wishlist_items.id,
|
||||
gameId: wishlist_items.game_id,
|
||||
gameName: games.name,
|
||||
gameThumbUrl: games.thumb_url,
|
||||
},
|
||||
})
|
||||
.from(wishlists)
|
||||
.leftJoin(wishlist_items, eq(wishlists.id, wishlist_items.wishlist_id))
|
||||
.leftJoin(games, eq(games.id, wishlist_items.game_id))
|
||||
.where(eq(wishlists.id, params.id));
|
||||
return {
|
||||
wishlist
|
||||
wishlist,
|
||||
};
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
|
@ -46,27 +48,27 @@ export const actions: Actions = {
|
|||
|
||||
if (!params?.id) {
|
||||
throw fail(400, {
|
||||
message: 'Invalid Request'
|
||||
message: 'Invalid Request',
|
||||
});
|
||||
}
|
||||
|
||||
const game = await db.query.games.findFirst({
|
||||
where: eq(games.id, form.id)
|
||||
where: eq(games.id, form.id),
|
||||
});
|
||||
|
||||
if (!game) {
|
||||
return fail(400, {
|
||||
message: 'Game not found'
|
||||
message: 'Game not found',
|
||||
});
|
||||
}
|
||||
|
||||
const wishlist = await db.query.wishlists.findFirst({
|
||||
where: eq(wishlists.id, params.id)
|
||||
where: eq(wishlists.id, params.id),
|
||||
});
|
||||
|
||||
if (wishlist?.user_id !== locals.user.id) {
|
||||
return fail(401, {
|
||||
message: 'Unauthorized'
|
||||
message: 'Unauthorized',
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -76,17 +78,17 @@ export const actions: Actions = {
|
|||
|
||||
const wishlistItem = await db.insert(wishlist_items).values({
|
||||
game_id: game.id,
|
||||
wishlist_id: wishlist.id
|
||||
wishlist_id: wishlist.id,
|
||||
});
|
||||
|
||||
if (!wishlistItem) {
|
||||
return fail(500, {
|
||||
message: 'Something went wrong'
|
||||
message: 'Something went wrong',
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
form
|
||||
form,
|
||||
};
|
||||
},
|
||||
// Create new wishlist
|
||||
|
|
@ -96,15 +98,15 @@ export const actions: Actions = {
|
|||
}
|
||||
},
|
||||
// Delete a wishlist
|
||||
delete: async ({ locals}) => {
|
||||
delete: async ({ locals }) => {
|
||||
if (!locals.user) {
|
||||
throw fail(401);
|
||||
}
|
||||
},
|
||||
// Remove game from a wishlist
|
||||
remove: async ({ locals }) => {
|
||||
remove: async ({ locals }) => {
|
||||
if (!locals.user) {
|
||||
throw fail(401);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ import { message, setError, superValidate } from 'sveltekit-superforms/server';
|
|||
import { redirect } from 'sveltekit-flash-message/server';
|
||||
import { changeEmailSchema, profileSchema } from '$lib/validations/account';
|
||||
import { notSignedInMessage } from '$lib/flashMessages';
|
||||
import db from '$lib/drizzle';
|
||||
import db from '../../../../db';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { users } from '../../../../schema';
|
||||
import { users } from '$db/schema';
|
||||
|
||||
export const load: PageServerLoad = async (event) => {
|
||||
if (!event.locals.user) {
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ import { setError, superValidate } from 'sveltekit-superforms/server';
|
|||
import { redirect } from 'sveltekit-flash-message/server';
|
||||
import { Argon2id } from 'oslo/password';
|
||||
import type { PageServerLoad } from '../../../$types';
|
||||
import db from '$lib/drizzle';
|
||||
import db from '../../../../../../../db';
|
||||
import { changeUserPasswordSchema } from '$lib/validations/account';
|
||||
import { lucia } from '$lib/server/auth.js';
|
||||
import { users } from '../../../../../../../schema';
|
||||
import { users } from '$db/schema';
|
||||
import { notSignedInMessage } from '$lib/flashMessages';
|
||||
import type { Cookie } from 'lucia';
|
||||
|
||||
|
|
@ -23,10 +23,10 @@ export const load: PageServerLoad = async (event) => {
|
|||
form.data = {
|
||||
current_password: '',
|
||||
password: '',
|
||||
confirm_password: ''
|
||||
confirm_password: '',
|
||||
};
|
||||
return {
|
||||
form
|
||||
form,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ export const actions: Actions = {
|
|||
|
||||
if (!form.valid) {
|
||||
return fail(400, {
|
||||
form
|
||||
form,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ export const actions: Actions = {
|
|||
const user = event.locals.user;
|
||||
|
||||
const dbUser = await db.query.users.findFirst({
|
||||
where: eq(users.id, user.id)
|
||||
where: eq(users.id, user.id),
|
||||
});
|
||||
|
||||
if (!dbUser?.hashed_password) {
|
||||
|
|
@ -61,13 +61,13 @@ export const actions: Actions = {
|
|||
form.data.current_password = '';
|
||||
return setError(
|
||||
form,
|
||||
'Error occurred. Please try again or contact support if you need further help.'
|
||||
'Error occurred. Please try again or contact support if you need further help.',
|
||||
);
|
||||
}
|
||||
|
||||
const currentPasswordVerified = await new Argon2id().verify(
|
||||
dbUser.hashed_password,
|
||||
form.data.current_password
|
||||
form.data.current_password,
|
||||
);
|
||||
|
||||
if (!currentPasswordVerified) {
|
||||
|
|
@ -86,7 +86,7 @@ export const actions: Actions = {
|
|||
.set({ hashed_password: hashedPassword })
|
||||
.where(eq(users.id, user.id));
|
||||
await lucia.createSession(user.id, {
|
||||
country: event.locals.session?.ipCountry ?? 'unknown'
|
||||
country: event.locals.session?.ipCountry ?? 'unknown',
|
||||
});
|
||||
sessionCookie = lucia.createBlankSessionCookie();
|
||||
} catch (e) {
|
||||
|
|
@ -98,23 +98,23 @@ export const actions: Actions = {
|
|||
}
|
||||
event.cookies.set(sessionCookie.name, sessionCookie.value, {
|
||||
path: '.',
|
||||
...sessionCookie.attributes
|
||||
...sessionCookie.attributes,
|
||||
});
|
||||
|
||||
const message = {
|
||||
type: 'success',
|
||||
message: 'Password Updated. Please sign in.'
|
||||
message: 'Password Updated. Please sign in.',
|
||||
} as const;
|
||||
redirect(302, '/login', message, event);
|
||||
}
|
||||
return setError(
|
||||
form,
|
||||
'Error occurred. Please try again or contact support if you need further help.'
|
||||
'Error occurred. Please try again or contact support if you need further help.',
|
||||
);
|
||||
// TODO: Add toast instead?
|
||||
// form.data.password = '';
|
||||
// form.data.confirm_password = '';
|
||||
// form.data.current_password = '';
|
||||
// return message(form, 'Profile updated successfully.');
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import { redirect, setFlash } from 'sveltekit-flash-message/server';
|
|||
import type { PageServerLoad } from '../../$types';
|
||||
import { addTwoFactorSchema, removeTwoFactorSchema } from '$lib/validations/account';
|
||||
import { notSignedInMessage } from '$lib/flashMessages';
|
||||
import db from '$lib/drizzle';
|
||||
import { recovery_codes, users } from '../../../../../../schema';
|
||||
import db from '../../../../../../db';
|
||||
import { recovery_codes, users } from '$db/schema';
|
||||
|
||||
export const load: PageServerLoad = async (event) => {
|
||||
const addTwoFactorForm = await superValidate(event, zod(addTwoFactorSchema));
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import db from '$lib/drizzle';
|
||||
import db from '../../../../../../../db';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { Argon2id } from 'oslo/password';
|
||||
import { alphabet, generateRandomString } from 'oslo/crypto';
|
||||
import { redirect } from 'sveltekit-flash-message/server';
|
||||
import { notSignedInMessage } from '$lib/flashMessages';
|
||||
import type { PageServerLoad } from '../../../$types';
|
||||
import { recovery_codes, users } from '../../../../../../../schema';
|
||||
import { recovery_codes, users } from '$db/schema';
|
||||
|
||||
export const load: PageServerLoad = async (event) => {
|
||||
const user = event.locals.user;
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ import { zod } from 'sveltekit-superforms/adapters';
|
|||
import { superValidate } from 'sveltekit-superforms/server';
|
||||
import { redirect } from 'sveltekit-flash-message/server';
|
||||
import { modifyListGameSchema } from '$lib/validations/zod-schemas';
|
||||
import db from '$lib/drizzle.js';
|
||||
import db from '../../../../db';
|
||||
import { notSignedInMessage } from '$lib/flashMessages.js';
|
||||
import { games, wishlist_items, wishlists } from '../../../../schema.js';
|
||||
import { games, wishlist_items, wishlists } from '$db/schema';
|
||||
|
||||
export async function load(event) {
|
||||
const user = event.locals.user;
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ import { zod } from 'sveltekit-superforms/adapters';
|
|||
import { superValidate } from 'sveltekit-superforms/server';
|
||||
import { redirect } from 'sveltekit-flash-message/server';
|
||||
import { modifyListGameSchema } from '$lib/validations/zod-schemas';
|
||||
import db from '$lib/drizzle.js';
|
||||
import db from '../../../../../db';
|
||||
import { notSignedInMessage } from '$lib/flashMessages.js';
|
||||
import { games, wishlist_items, wishlists } from '../../../../../schema.js';
|
||||
import { games, wishlist_items, wishlists } from '$db/schema';
|
||||
|
||||
export async function load(event) {
|
||||
const { params, locals } = event;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import type { MetaTagsProps } from 'svelte-meta-tags';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import db from '$lib/drizzle';
|
||||
import { collections, wishlists } from '../../schema';
|
||||
import db from '../../db';
|
||||
import { collections, wishlists } from '$db/schema';
|
||||
|
||||
export const load: PageServerLoad = async ({ locals, url }) => {
|
||||
const image = {
|
||||
|
|
|
|||
|
|
@ -6,9 +6,16 @@ import { createMechanic } from '$lib/utils/db/mechanicUtils';
|
|||
import { createPublisher } from '$lib/utils/db/publisherUtils';
|
||||
import { createExpansion } from '$lib/utils/db/expansionUtils';
|
||||
import { createOrUpdateGame } from '$lib/utils/db/gameUtils';
|
||||
import db from '$lib/drizzle';
|
||||
import db from '../../../../db';
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
import { collection_items, collections, expansions, games, wishlist_items, wishlists } from '../../../../schema';
|
||||
import {
|
||||
collection_items,
|
||||
collections,
|
||||
expansions,
|
||||
games,
|
||||
wishlist_items,
|
||||
wishlists,
|
||||
} from '$db/schema';
|
||||
|
||||
export const load: PageServerLoad = async ({ params, locals, fetch }) => {
|
||||
try {
|
||||
|
|
@ -22,32 +29,32 @@ export const load: PageServerLoad = async ({ params, locals, fetch }) => {
|
|||
publisher: {
|
||||
columns: {
|
||||
id: true,
|
||||
name: true
|
||||
}
|
||||
}
|
||||
}
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
mechanics_to_games: {
|
||||
with: {
|
||||
mechanic: {
|
||||
columns: {
|
||||
id: true,
|
||||
name: true
|
||||
}
|
||||
}
|
||||
}
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
categories_to_games: {
|
||||
with: {
|
||||
category: {
|
||||
columns: {
|
||||
id: true,
|
||||
name: true
|
||||
}
|
||||
}
|
||||
}
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
});
|
||||
console.log('found game', game);
|
||||
|
||||
|
|
@ -71,10 +78,10 @@ export const load: PageServerLoad = async ({ params, locals, fetch }) => {
|
|||
columns: {
|
||||
id: true,
|
||||
name: true,
|
||||
thumb_url: true
|
||||
}
|
||||
}
|
||||
}
|
||||
thumb_url: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
let collectionItem;
|
||||
|
|
@ -87,8 +94,11 @@ export const load: PageServerLoad = async ({ params, locals, fetch }) => {
|
|||
// TODO: Select wishlist items based on wishlist
|
||||
if (wishlist) {
|
||||
wishlistItem = await db.query.wishlist_items.findFirst({
|
||||
where: and(eq(wishlist_items.wishlist_id, wishlist.id), eq(wishlist_items.game_id, game.id)),
|
||||
})
|
||||
where: and(
|
||||
eq(wishlist_items.wishlist_id, wishlist.id),
|
||||
eq(wishlist_items.game_id, game.id),
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
const collection = await db.query.collections.findFirst({
|
||||
|
|
@ -99,8 +109,11 @@ export const load: PageServerLoad = async ({ params, locals, fetch }) => {
|
|||
|
||||
if (collection) {
|
||||
collectionItem = await db.query.collection_items.findFirst({
|
||||
where: and(eq(collection_items.collection_id, collection.id), eq(collection_items.game_id, game.id)),
|
||||
})
|
||||
where: and(
|
||||
eq(collection_items.collection_id, collection.id),
|
||||
eq(collection_items.game_id, game.id),
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -122,7 +135,7 @@ export const load: PageServerLoad = async ({ params, locals, fetch }) => {
|
|||
|
||||
async function syncGameAndConnectedData(locals: App.Locals, game: Game, eventFetch: Function) {
|
||||
console.log(
|
||||
`Retrieving full external game details for external id: ${game.external_id} with name ${game.name}`
|
||||
`Retrieving full external game details for external id: ${game.external_id} with name ${game.name}`,
|
||||
);
|
||||
const externalGameResponse = await eventFetch(`/api/external/game/${game.external_id}`);
|
||||
if (externalGameResponse.ok) {
|
||||
|
|
@ -134,7 +147,7 @@ async function syncGameAndConnectedData(locals: App.Locals, game: Game, eventFet
|
|||
for (const externalCategory of externalGame.categories) {
|
||||
const category = await createCategory(locals, externalCategory, externalGame.external_id);
|
||||
categories.push({
|
||||
id: category.id
|
||||
id: category.id,
|
||||
});
|
||||
}
|
||||
for (const externalMechanic of externalGame.mechanics) {
|
||||
|
|
@ -151,7 +164,7 @@ async function syncGameAndConnectedData(locals: App.Locals, game: Game, eventFet
|
|||
if (externalExpansion?.inbound === true) {
|
||||
createExpansion(locals, externalExpansion);
|
||||
} else {
|
||||
createExpansion(locals,externalExpansion);
|
||||
createExpansion(locals, externalExpansion);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ import { zod } from 'sveltekit-superforms/adapters';
|
|||
import { setError, superValidate } from 'sveltekit-superforms/server';
|
||||
import { redirect } from 'sveltekit-flash-message/server';
|
||||
import { RateLimiter } from 'sveltekit-rate-limiter/server';
|
||||
import db from '$lib/drizzle';
|
||||
import db from '../../../db';
|
||||
import { lucia } from '$lib/server/auth';
|
||||
import { signInSchema } from '$lib/validations/auth';
|
||||
import { users, recovery_codes } from '../../../schema';
|
||||
import { users, recovery_codes } from '$db/schema';
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async (event) => {
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
import {fail, error, type Actions} from '@sveltejs/kit';
|
||||
import {Argon2id} from 'oslo/password';
|
||||
import {eq} from 'drizzle-orm';
|
||||
import {zod} from 'sveltekit-superforms/adapters';
|
||||
import {setError, superValidate} from 'sveltekit-superforms/server';
|
||||
import {redirect} from 'sveltekit-flash-message/server';
|
||||
import {RateLimiter} from 'sveltekit-rate-limiter/server';
|
||||
import type {PageServerLoad} from './$types';
|
||||
import {lucia} from '$lib/server/auth';
|
||||
import {signUpSchema} from '$lib/validations/auth';
|
||||
import {add_user_to_role} from '$server/roles';
|
||||
import db from '$lib/drizzle';
|
||||
import {collections, users, wishlists} from '../../../schema';
|
||||
import {createId as cuid2} from '@paralleldrive/cuid2';
|
||||
import { fail, error, type Actions } from '@sveltejs/kit';
|
||||
import { Argon2id } from 'oslo/password';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { zod } from 'sveltekit-superforms/adapters';
|
||||
import { setError, superValidate } from 'sveltekit-superforms/server';
|
||||
import { redirect } from 'sveltekit-flash-message/server';
|
||||
import { RateLimiter } from 'sveltekit-rate-limiter/server';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { lucia } from '$lib/server/auth';
|
||||
import { signUpSchema } from '$lib/validations/auth';
|
||||
import { add_user_to_role } from '$server/roles';
|
||||
import db from '../../../db';
|
||||
import { collections, users, wishlists } from '$db/schema';
|
||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||
|
||||
const limiter = new RateLimiter({
|
||||
// A rate is defined by [number, unit]
|
||||
IPUA: [5, 'm']
|
||||
IPUA: [5, 'm'],
|
||||
});
|
||||
|
||||
const signUpDefaults = {
|
||||
|
|
@ -25,7 +25,7 @@ const signUpDefaults = {
|
|||
username: '',
|
||||
password: '',
|
||||
confirm_password: '',
|
||||
terms: true
|
||||
terms: true,
|
||||
};
|
||||
|
||||
export const load: PageServerLoad = async (event) => {
|
||||
|
|
@ -37,14 +37,14 @@ export const load: PageServerLoad = async (event) => {
|
|||
// );
|
||||
|
||||
if (event.locals.user) {
|
||||
const message = {type: 'success', message: 'You are already signed in'} as const;
|
||||
const message = { type: 'success', message: 'You are already signed in' } as const;
|
||||
throw redirect('/', message, event);
|
||||
}
|
||||
|
||||
return {
|
||||
form: await superValidate(zod(signUpSchema), {
|
||||
defaults: signUpDefaults
|
||||
})
|
||||
defaults: signUpDefaults,
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ export const actions: Actions = {
|
|||
form.data.password = '';
|
||||
form.data.confirm_password = '';
|
||||
return fail(400, {
|
||||
form
|
||||
form,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ export const actions: Actions = {
|
|||
console.log('Check if user already exists');
|
||||
|
||||
const existing_user = await db.query.users.findFirst({
|
||||
where: eq(users.username, form.data.username)
|
||||
where: eq(users.username, form.data.username),
|
||||
});
|
||||
|
||||
if (existing_user) {
|
||||
|
|
@ -81,41 +81,41 @@ export const actions: Actions = {
|
|||
const hashedPassword = await new Argon2id().hash(form.data.password);
|
||||
|
||||
const user = await db
|
||||
.insert(users)
|
||||
.values({
|
||||
username: form.data.username,
|
||||
hashed_password: hashedPassword,
|
||||
email: form.data.email,
|
||||
first_name: form.data.firstName ?? '',
|
||||
last_name: form.data.lastName ?? '',
|
||||
verified: false,
|
||||
receive_email: false,
|
||||
theme: 'system',
|
||||
two_factor_secret: '',
|
||||
two_factor_enabled: false
|
||||
})
|
||||
.returning();
|
||||
.insert(users)
|
||||
.values({
|
||||
username: form.data.username,
|
||||
hashed_password: hashedPassword,
|
||||
email: form.data.email,
|
||||
first_name: form.data.firstName ?? '',
|
||||
last_name: form.data.lastName ?? '',
|
||||
verified: false,
|
||||
receive_email: false,
|
||||
theme: 'system',
|
||||
two_factor_secret: '',
|
||||
two_factor_enabled: false,
|
||||
})
|
||||
.returning();
|
||||
console.log('signup user', user);
|
||||
|
||||
if (!user || user.length === 0) {
|
||||
return fail(400, {
|
||||
form,
|
||||
message: `Could not create your account. Please try again. If the problem persists, please contact support. Error ID: ${cuid2()}`
|
||||
message: `Could not create your account. Please try again. If the problem persists, please contact support. Error ID: ${cuid2()}`,
|
||||
});
|
||||
}
|
||||
|
||||
add_user_to_role(user[0].id, 'user', true);
|
||||
await db.insert(collections).values({
|
||||
user_id: user[0].id
|
||||
user_id: user[0].id,
|
||||
});
|
||||
await db.insert(wishlists).values({
|
||||
user_id: user[0].id
|
||||
user_id: user[0].id,
|
||||
});
|
||||
|
||||
try {
|
||||
session = await lucia.createSession(user[0].id, {
|
||||
ip_country: event.locals.ip,
|
||||
ip_address: event.locals.country
|
||||
ip_address: event.locals.country,
|
||||
});
|
||||
sessionCookie = lucia.createSessionCookie(session.id);
|
||||
} catch (e: any) {
|
||||
|
|
@ -126,7 +126,7 @@ export const actions: Actions = {
|
|||
console.log(e);
|
||||
const message = {
|
||||
type: 'error',
|
||||
message: 'Unable to create your account. Please try again.'
|
||||
message: 'Unable to create your account. Please try again.',
|
||||
};
|
||||
form.data.password = '';
|
||||
form.data.confirm_password = '';
|
||||
|
|
@ -135,11 +135,11 @@ export const actions: Actions = {
|
|||
|
||||
event.cookies.set(sessionCookie.name, sessionCookie.value, {
|
||||
path: '.',
|
||||
...sessionCookie.attributes
|
||||
...sessionCookie.attributes,
|
||||
});
|
||||
|
||||
redirect(302, '/');
|
||||
// const message = { type: 'success', message: 'Signed Up!' } as const;
|
||||
// throw flashRedirect(message, event);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import db from '$lib/drizzle.js';
|
||||
import db from '../../../../db';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { users } from '../../../../schema.js';
|
||||
import { users } from '$db/schema';
|
||||
import { createPasswordResetToken } from '$lib/server/auth-utils.js';
|
||||
import { PUBLIC_SITE_URL } from '$env/static/public';
|
||||
|
||||
|
|
@ -13,11 +13,13 @@ export async function POST({ locals, request }) {
|
|||
}
|
||||
|
||||
const user = await db.query.users.findFirst({
|
||||
where: eq(users.email, email)
|
||||
where: eq(users.email, email),
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
error(200, { message: 'Email sent! Please check your email for a link to reset your password.' });
|
||||
error(200, {
|
||||
message: 'Email sent! Please check your email for a link to reset your password.',
|
||||
});
|
||||
}
|
||||
|
||||
const verificationToken = await createPasswordResetToken(user.id);
|
||||
|
|
@ -27,6 +29,6 @@ export async function POST({ locals, request }) {
|
|||
console.log('Verification link: ' + verificationLink);
|
||||
|
||||
return new Response(null, {
|
||||
status: 200
|
||||
status: 200,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import db from '$lib/drizzle.js';
|
||||
import db from '../../../../../db';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { password_reset_tokens, users } from '../../../../../schema.js';
|
||||
import { password_reset_tokens, users } from '$db/schema';
|
||||
import { isWithinExpirationDate } from 'oslo';
|
||||
import { lucia } from '$lib/server/auth.js';
|
||||
import { Argon2id } from 'oslo/password';
|
||||
|
|
@ -10,34 +10,31 @@ export async function POST({ request, params }) {
|
|||
|
||||
if (typeof password !== 'string' || password.length < 8) {
|
||||
return new Response(null, {
|
||||
status: 400
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
const verificationToken = params.token;
|
||||
|
||||
const token = await db.query.password_reset_tokens.findFirst({
|
||||
where: eq(password_reset_tokens.id, verificationToken)
|
||||
where: eq(password_reset_tokens.id, verificationToken),
|
||||
});
|
||||
if (!token) {
|
||||
await db.delete(password_reset_tokens).where(eq(password_reset_tokens.id, verificationToken));
|
||||
return new Response(null, {
|
||||
status: 400
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
if (!token?.expires_at || !isWithinExpirationDate(token.expires_at)) {
|
||||
return new Response(null, {
|
||||
status: 400
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
await lucia.invalidateUserSessions(token.user_id);
|
||||
const hashPassword = await new Argon2id().hash(password);
|
||||
await db
|
||||
.update(users)
|
||||
.set({ hashed_password: hashPassword })
|
||||
.where(eq(users.id, token.user_id));
|
||||
await db.update(users).set({ hashed_password: hashPassword }).where(eq(users.id, token.user_id));
|
||||
|
||||
const session = await lucia.createSession(token.user_id, {});
|
||||
const sessionCookie = lucia.createSessionCookie(session.id);
|
||||
|
|
@ -45,8 +42,8 @@ export async function POST({ request, params }) {
|
|||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: {
|
||||
Location: "/",
|
||||
"Set-Cookie": sessionCookie.serialize()
|
||||
}
|
||||
Location: '/',
|
||||
'Set-Cookie': sessionCookie.serialize(),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { error, json } from '@sveltejs/kit';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import db from '$lib/drizzle.js';
|
||||
import { collection_items, users } from '../../../../../schema.js';
|
||||
import db from '../../../../../db';
|
||||
import { collection_items, users } from '$db/schema';
|
||||
|
||||
// Search a user's collection
|
||||
export async function GET({ url, locals, params }) {
|
||||
|
|
@ -20,7 +20,7 @@ export async function GET({ url, locals, params }) {
|
|||
}
|
||||
|
||||
const collection = await db.query.collections.findFirst({
|
||||
where: eq(users.id, locals?.user?.id)
|
||||
where: eq(users.id, locals?.user?.id),
|
||||
});
|
||||
console.log('collection', collection);
|
||||
|
||||
|
|
@ -37,12 +37,13 @@ export async function GET({ url, locals, params }) {
|
|||
columns: {
|
||||
id: true,
|
||||
name: true,
|
||||
thumb_url: true
|
||||
thumb_url: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
orderBy: (collection_items, { asc, desc }) => {
|
||||
const dbSort = sort === 'dateAdded' ? collection_items.created_at : collection_items.times_played;
|
||||
const dbSort =
|
||||
sort === 'dateAdded' ? collection_items.created_at : collection_items.times_played;
|
||||
if (order === 'asc') {
|
||||
return asc(dbSort);
|
||||
} else {
|
||||
|
|
@ -50,7 +51,7 @@ export async function GET({ url, locals, params }) {
|
|||
}
|
||||
},
|
||||
offset: skip,
|
||||
limit
|
||||
limit,
|
||||
});
|
||||
|
||||
return json(userCollectionItems);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import db from '$lib/drizzle.js';
|
||||
import db from '../../../../db';
|
||||
import { error, json } from '@sveltejs/kit';
|
||||
import { asc, count } from 'drizzle-orm';
|
||||
import { games, type Games } from '../../../../schema.js';
|
||||
import { games, type Games } from '$db/schema';
|
||||
|
||||
export const GET = async ({ url }) => {
|
||||
const searchParams = Object.fromEntries(url.searchParams);
|
||||
|
|
@ -14,12 +14,13 @@ export const GET = async ({ url }) => {
|
|||
try {
|
||||
const totalGames = await db
|
||||
.select({
|
||||
value: count(games.id)
|
||||
value: count(games.id),
|
||||
})
|
||||
.from(games);
|
||||
const numberOfGames = totalGames[0].value || 0;
|
||||
const randomIndex = Math.floor(Math.random() * numberOfGames);
|
||||
const randomGames: Games[] = await db.select()
|
||||
const randomGames: Games[] = await db
|
||||
.select()
|
||||
.from(games)
|
||||
.orderBy(asc(games.id))
|
||||
.limit(limit)
|
||||
|
|
@ -29,4 +30,4 @@ export const GET = async ({ url }) => {
|
|||
console.error(e);
|
||||
throw error(500, { message: 'Something went wrong' });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { error, json } from '@sveltejs/kit';
|
||||
import db from '$lib/drizzle.js';
|
||||
import {asc, desc, eq, ilike, or } from 'drizzle-orm';
|
||||
import { games } from '../../../../schema.js';
|
||||
import kebabCase from "just-kebab-case";
|
||||
import db from '../../../../db';
|
||||
import { asc, desc, eq, ilike, or } from 'drizzle-orm';
|
||||
import { games } from '$db/schema';
|
||||
import kebabCase from 'just-kebab-case';
|
||||
|
||||
// Search a user's collection
|
||||
export const GET = async ({ url, locals }) => {
|
||||
|
|
@ -17,20 +17,21 @@ export const GET = async ({ url, locals }) => {
|
|||
if (orderBy === 'name') {
|
||||
orderBy = 'slug';
|
||||
}
|
||||
console.log(`q: ${q}, limit: ${limit}, skip: ${skip}, order: ${order}, exact: ${exact}, orderBy: ${orderBy}`);
|
||||
console.log(
|
||||
`q: ${q}, limit: ${limit}, skip: ${skip}, order: ${order}, exact: ${exact}, orderBy: ${orderBy}`,
|
||||
);
|
||||
console.log(exact);
|
||||
if (exact) {
|
||||
console.log('Exact Search API');
|
||||
const game =
|
||||
await db.query.games.findFirst({
|
||||
where: eq(games.name, q),
|
||||
columns: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
thumb_url: true
|
||||
}
|
||||
});
|
||||
const game = await db.query.games.findFirst({
|
||||
where: eq(games.name, q),
|
||||
columns: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
thumb_url: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!game) {
|
||||
error(404, { message: 'No games found' });
|
||||
|
|
@ -39,20 +40,19 @@ export const GET = async ({ url, locals }) => {
|
|||
console.log('Games found in Exact Search API', JSON.stringify(foundGames, null, 2));
|
||||
return json(foundGames);
|
||||
} else {
|
||||
const foundGames = await db.select({
|
||||
id: games.id,
|
||||
name: games.name,
|
||||
slug: games.slug,
|
||||
thumb_url: games.thumb_url
|
||||
})
|
||||
const foundGames =
|
||||
(await db
|
||||
.select({
|
||||
id: games.id,
|
||||
name: games.name,
|
||||
slug: games.slug,
|
||||
thumb_url: games.thumb_url,
|
||||
})
|
||||
.from(games)
|
||||
.where(or(
|
||||
ilike(games.name, `%${q}%`),
|
||||
ilike(games.slug, `%${kebabCase(q)}%`)
|
||||
))
|
||||
.where(or(ilike(games.name, `%${q}%`), ilike(games.slug, `%${kebabCase(q)}%`)))
|
||||
.orderBy(getOrderDirection(order)(getOrderBy(orderBy)))
|
||||
.offset(skip)
|
||||
.limit(limit) || [];
|
||||
.limit(limit)) || [];
|
||||
// const foundGames = await db.select({
|
||||
// id: games.id,
|
||||
// name: games.name,
|
||||
|
|
@ -73,7 +73,7 @@ export const GET = async ({ url, locals }) => {
|
|||
type OrderDirection = 'asc' | 'desc';
|
||||
|
||||
const getOrderDirection = (direction: OrderDirection) => {
|
||||
return direction === 'asc' ? asc: desc;
|
||||
return direction === 'asc' ? asc : desc;
|
||||
};
|
||||
|
||||
const getOrderBy = (orderBy: string) => {
|
||||
|
|
@ -85,4 +85,4 @@ const getOrderBy = (orderBy: string) => {
|
|||
default:
|
||||
return games.slug;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { createPublisher } from '$lib/utils/db/publisherUtils.js';
|
||||
import type { Publishers } from '../../../schema.js';
|
||||
import type { Publishers } from '$db/schema';
|
||||
|
||||
type PublisherCreate = {
|
||||
publisher: Publishers;
|
||||
externalId: string;
|
||||
}
|
||||
};
|
||||
|
||||
export async function POST({ request, locals }) {
|
||||
const data: PublisherCreate = await request.json();
|
||||
|
|
@ -15,7 +15,7 @@ export async function POST({ request, locals }) {
|
|||
} catch (e) {
|
||||
console.error(e);
|
||||
return new Response('Could not create publisher', {
|
||||
status: 500
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { getPublisher, updatePublisher } from '$lib/utils/db/publisherUtils.js';
|
||||
import type { Publishers } from '../../../../schema.js';
|
||||
import type { Publishers } from '$db/schema';
|
||||
|
||||
export async function GET({ locals, params }) {
|
||||
try {
|
||||
|
|
@ -7,7 +7,7 @@ export async function GET({ locals, params }) {
|
|||
} catch (e) {
|
||||
console.error(e);
|
||||
return new Response('Could not get publishers', {
|
||||
status: 500
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -16,4 +16,4 @@ export async function PUT({ locals, params, request }) {
|
|||
const data: Publishers = await request.json();
|
||||
const publisherId = params.id;
|
||||
return await updatePublisher(locals, data, publisherId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { error, json } from '@sveltejs/kit';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import db from '$lib/drizzle.js';
|
||||
import { wishlist_items, wishlists } from '../../../../../schema.js';
|
||||
import db from '../../../../../db';
|
||||
import { wishlist_items, wishlists } from '$db/schema';
|
||||
|
||||
// Search a user's collection
|
||||
export async function GET({ url, locals, params }) {
|
||||
|
|
@ -16,12 +16,12 @@ export async function GET({ url, locals, params }) {
|
|||
|
||||
if (!locals.user) {
|
||||
return new Response(null, {
|
||||
status: 401
|
||||
status: 401,
|
||||
});
|
||||
}
|
||||
|
||||
const wishlist = await db.query.wishlists.findFirst({
|
||||
where: eq(wishlists.user_id, locals?.user?.id)
|
||||
where: eq(wishlists.user_id, locals?.user?.id),
|
||||
});
|
||||
console.log('wishlist', wishlist);
|
||||
|
||||
|
|
@ -38,9 +38,9 @@ export async function GET({ url, locals, params }) {
|
|||
columns: {
|
||||
id: true,
|
||||
name: true,
|
||||
thumb_url: true
|
||||
}
|
||||
}
|
||||
thumb_url: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: (wishlist_items, { asc, desc }) => {
|
||||
const dbSort = wishlist_items.created_at;
|
||||
|
|
@ -51,7 +51,7 @@ export async function GET({ url, locals, params }) {
|
|||
}
|
||||
},
|
||||
offset: skip,
|
||||
limit
|
||||
limit,
|
||||
});
|
||||
|
||||
return json(itemsInWishlist);
|
||||
|
|
|
|||
549
src/schema.ts
549
src/schema.ts
|
|
@ -1,549 +0,0 @@
|
|||
import { relations, sql, type InferSelectModel } from 'drizzle-orm';
|
||||
import {
|
||||
pgTable,
|
||||
timestamp,
|
||||
text,
|
||||
boolean,
|
||||
integer,
|
||||
index,
|
||||
pgEnum,
|
||||
primaryKey,
|
||||
uuid,
|
||||
} from 'drizzle-orm/pg-core';
|
||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||
import { tsvector } from './tsVector';
|
||||
|
||||
// User Related Schemas
|
||||
|
||||
export const users = pgTable('users', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
username: text('username').unique(),
|
||||
hashed_password: text('hashed_password'),
|
||||
email: text('email').unique(),
|
||||
first_name: text('first_name'),
|
||||
last_name: text('last_name'),
|
||||
verified: boolean('verified').default(false),
|
||||
receive_email: boolean('receive_email').default(false),
|
||||
theme: text('theme').default('system'),
|
||||
two_factor_secret: text('two_factor_secret').default(''),
|
||||
two_factor_enabled: boolean('two_factor_enabled').default(false),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export const recovery_codes = pgTable('recovery_codes', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
userId: uuid('user_id')
|
||||
.notNull()
|
||||
.references(() => users.id),
|
||||
code: text('code').notNull(),
|
||||
used: boolean('used').default(false),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export type RecoveryCodes = InferSelectModel<typeof recovery_codes>;
|
||||
|
||||
export const user_relations = relations(users, ({ many }) => ({
|
||||
user_roles: many(user_roles),
|
||||
}));
|
||||
|
||||
export type Users = InferSelectModel<typeof users>;
|
||||
|
||||
export const sessions = pgTable('sessions', {
|
||||
id: text('id').primaryKey(),
|
||||
userId: uuid('user_id')
|
||||
.notNull()
|
||||
.references(() => users.id),
|
||||
expiresAt: timestamp('expires_at', {
|
||||
withTimezone: true,
|
||||
mode: 'date',
|
||||
}).notNull(),
|
||||
ipCountry: text('ip_country'),
|
||||
ipAddress: text('ip_address'),
|
||||
});
|
||||
|
||||
export const roles = pgTable('roles', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2())
|
||||
.notNull(),
|
||||
name: text('name').unique().notNull(),
|
||||
});
|
||||
|
||||
export type Roles = InferSelectModel<typeof roles>;
|
||||
|
||||
export const role_relations = relations(roles, ({ many }) => ({
|
||||
user_roles: many(user_roles),
|
||||
}));
|
||||
|
||||
export const user_roles = pgTable('user_roles', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
user_id: uuid('user_id')
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: 'cascade' }),
|
||||
role_id: uuid('role_id')
|
||||
.notNull()
|
||||
.references(() => roles.id, { onDelete: 'cascade' }),
|
||||
primary: boolean('primary').default(false),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export const user_role_relations = relations(user_roles, ({ one }) => ({
|
||||
role: one(roles, {
|
||||
fields: [user_roles.role_id],
|
||||
references: [roles.id],
|
||||
}),
|
||||
user: one(users, {
|
||||
fields: [user_roles.user_id],
|
||||
references: [users.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export type UserRoles = InferSelectModel<typeof user_roles>;
|
||||
|
||||
export const password_reset_tokens = pgTable('password_reset_tokens', {
|
||||
id: text('id')
|
||||
.primaryKey()
|
||||
.$defaultFn(() => cuid2()),
|
||||
user_id: uuid('user_id')
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: 'cascade' }),
|
||||
expires_at: timestamp('expires_at', {
|
||||
withTimezone: true,
|
||||
mode: 'date',
|
||||
precision: 6,
|
||||
}),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export const password_reset_token_relations = relations(password_reset_tokens, ({ one }) => ({
|
||||
user: one(users, {
|
||||
fields: [password_reset_tokens.user_id],
|
||||
references: [users.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export const collections = pgTable('collections', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
user_id: uuid('user_id')
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: 'cascade' }),
|
||||
name: text('name').notNull().default('My Collection'),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export const collection_relations = relations(collections, ({ one }) => ({
|
||||
user: one(users, {
|
||||
fields: [collections.user_id],
|
||||
references: [users.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export const collection_items = pgTable('collection_items', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
collection_id: uuid('collection_id')
|
||||
.notNull()
|
||||
.references(() => collections.id, { onDelete: 'cascade' }),
|
||||
game_id: uuid('game_id')
|
||||
.notNull()
|
||||
.references(() => games.id, { onDelete: 'cascade' }),
|
||||
times_played: integer('times_played').default(0),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export type CollectionItems = InferSelectModel<typeof collection_items>;
|
||||
|
||||
export const collection_item_relations = relations(collection_items, ({ one }) => ({
|
||||
collection: one(collections, {
|
||||
fields: [collection_items.collection_id],
|
||||
references: [collections.id],
|
||||
}),
|
||||
game: one(games, {
|
||||
fields: [collection_items.game_id],
|
||||
references: [games.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export const wishlists = pgTable('wishlists', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
user_id: uuid('user_id')
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: 'cascade' }),
|
||||
name: text('name').notNull().default('My Wishlist'),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export type Wishlists = InferSelectModel<typeof wishlists>;
|
||||
|
||||
export const wishlists_relations = relations(wishlists, ({ one }) => ({
|
||||
user: one(users, {
|
||||
fields: [wishlists.user_id],
|
||||
references: [users.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export const wishlist_items = pgTable('wishlist_items', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
wishlist_id: uuid('wishlist_id')
|
||||
.notNull()
|
||||
.references(() => wishlists.id, { onDelete: 'cascade' }),
|
||||
game_id: uuid('game_id')
|
||||
.notNull()
|
||||
.references(() => games.id, { onDelete: 'cascade' }),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export type WishlistItems = InferSelectModel<typeof wishlist_items>;
|
||||
|
||||
export const wishlist_item_relations = relations(wishlist_items, ({ one }) => ({
|
||||
wishlist: one(wishlists, {
|
||||
fields: [wishlist_items.wishlist_id],
|
||||
references: [wishlists.id],
|
||||
}),
|
||||
game: one(games, {
|
||||
fields: [wishlist_items.game_id],
|
||||
references: [games.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
// Game and related table schemas
|
||||
|
||||
export const externalIdType = pgEnum('external_id_type', [
|
||||
'game',
|
||||
'category',
|
||||
'mechanic',
|
||||
'publisher',
|
||||
'designer',
|
||||
'artist',
|
||||
]);
|
||||
|
||||
export const externalIds = pgTable('external_ids', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
type: externalIdType('type').notNull(),
|
||||
externalId: text('external_id').notNull(),
|
||||
});
|
||||
|
||||
export type ExternalIds = InferSelectModel<typeof externalIds>;
|
||||
|
||||
export const games = pgTable(
|
||||
'games',
|
||||
{
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
name: text('name'),
|
||||
slug: text('slug'),
|
||||
description: text('description'),
|
||||
year_published: integer('year_published'),
|
||||
min_players: integer('min_players'),
|
||||
max_players: integer('max_players'),
|
||||
playtime: integer('playtime'),
|
||||
min_playtime: integer('min_playtime'),
|
||||
max_playtime: integer('max_playtime'),
|
||||
min_age: integer('min_age'),
|
||||
image_url: text('image_url'),
|
||||
thumb_url: text('thumb_url'),
|
||||
url: text('url'),
|
||||
text_searchable_index: tsvector('text_searchable_index'),
|
||||
last_sync_at: timestamp('last_sync_at', {
|
||||
withTimezone: true,
|
||||
mode: 'date',
|
||||
precision: 6,
|
||||
}),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
},
|
||||
(table) => {
|
||||
return {
|
||||
text_searchable_idx: index('text_searchable_idx')
|
||||
.on(table.text_searchable_index)
|
||||
.using(sql`'gin'`),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export type Games = InferSelectModel<typeof games>;
|
||||
|
||||
export const gamesToExternalIds = pgTable(
|
||||
'games_to_external_ids',
|
||||
{
|
||||
gameId: uuid('game_id')
|
||||
.notNull()
|
||||
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
externalId: uuid('external_id')
|
||||
.notNull()
|
||||
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
},
|
||||
(table) => {
|
||||
return {
|
||||
gamesToExternalIdsPkey: primaryKey({
|
||||
columns: [table.gameId, table.externalId],
|
||||
}),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const gameRelations = relations(games, ({ many }) => ({
|
||||
categories_to_games: many(categories_to_games),
|
||||
mechanics_to_games: many(mechanics_to_games),
|
||||
publishers_to_games: many(publishers_to_games),
|
||||
gamesToExternalIds: many(gamesToExternalIds),
|
||||
}));
|
||||
|
||||
export const expansions = pgTable('expansions', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
base_game_id: uuid('base_game_id')
|
||||
.notNull()
|
||||
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
game_id: uuid('game_id')
|
||||
.notNull()
|
||||
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export type Expansions = InferSelectModel<typeof expansions>;
|
||||
|
||||
export const expansion_relations = relations(expansions, ({ one }) => ({
|
||||
baseGame: one(games, {
|
||||
fields: [expansions.base_game_id],
|
||||
references: [games.id],
|
||||
}),
|
||||
game: one(games, {
|
||||
fields: [expansions.game_id],
|
||||
references: [games.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export const publishers = pgTable('publishers', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
name: text('name'),
|
||||
slug: text('slug'),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export type Publishers = InferSelectModel<typeof publishers>;
|
||||
|
||||
export const publishersToExternalIds = pgTable(
|
||||
'publishers_to_external_ids',
|
||||
{
|
||||
publisherId: uuid('publisher_id')
|
||||
.notNull()
|
||||
.references(() => publishers.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
externalId: uuid('external_id')
|
||||
.notNull()
|
||||
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
},
|
||||
(table) => {
|
||||
return {
|
||||
publishersToExternalIdsPkey: primaryKey({
|
||||
columns: [table.publisherId, table.externalId],
|
||||
}),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const publishers_relations = relations(publishers, ({ many }) => ({
|
||||
publishers_to_games: many(publishers_to_games),
|
||||
publishersToExternalIds: many(publishersToExternalIds),
|
||||
}));
|
||||
|
||||
export const categories = pgTable('categories', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
name: text('name'),
|
||||
slug: text('slug'),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export type Categories = InferSelectModel<typeof categories>;
|
||||
|
||||
export const categoriesToExternalIds = pgTable(
|
||||
'categories_to_external_ids',
|
||||
{
|
||||
categoryId: uuid('category_id')
|
||||
.notNull()
|
||||
.references(() => categories.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
externalId: uuid('external_id')
|
||||
.notNull()
|
||||
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
},
|
||||
(table) => {
|
||||
return {
|
||||
categoriesToExternalIdsPkey: primaryKey({
|
||||
columns: [table.categoryId, table.externalId],
|
||||
}),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const categories_to_games = pgTable(
|
||||
'categories_to_games',
|
||||
{
|
||||
category_id: uuid('category_id')
|
||||
.notNull()
|
||||
.references(() => categories.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
game_id: uuid('game_id')
|
||||
.notNull()
|
||||
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
},
|
||||
(table) => {
|
||||
return {
|
||||
categoriesToGamesPkey: primaryKey({
|
||||
columns: [table.category_id, table.game_id],
|
||||
}),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const categories_to_games_relations = relations(categories_to_games, ({ one }) => ({
|
||||
category: one(categories, {
|
||||
fields: [categories_to_games.category_id],
|
||||
references: [categories.id],
|
||||
}),
|
||||
game: one(games, {
|
||||
fields: [categories_to_games.game_id],
|
||||
references: [games.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export const categories_relations = relations(categories, ({ many }) => ({
|
||||
categories_to_games: many(categories_to_games),
|
||||
categoriesToExternalIds: many(categoriesToExternalIds),
|
||||
}));
|
||||
|
||||
export const mechanics = pgTable('mechanics', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
cuid: text('cuid')
|
||||
.unique()
|
||||
.$defaultFn(() => cuid2()),
|
||||
name: text('name'),
|
||||
slug: text('slug'),
|
||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export type Mechanics = InferSelectModel<typeof mechanics>;
|
||||
|
||||
export const mechanicsToExternalIds = pgTable(
|
||||
'mechanics_to_external_ids',
|
||||
{
|
||||
mechanicId: uuid('mechanic_id')
|
||||
.notNull()
|
||||
.references(() => mechanics.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
externalId: uuid('external_id')
|
||||
.notNull()
|
||||
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
},
|
||||
(table) => {
|
||||
return {
|
||||
mechanicsToExternalIdsPkey: primaryKey({
|
||||
columns: [table.mechanicId, table.externalId],
|
||||
}),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const mechanic_relations = relations(mechanics, ({ many }) => ({
|
||||
mechanics_to_games: many(mechanics_to_games),
|
||||
mechanicsToExternalIds: many(mechanicsToExternalIds),
|
||||
}));
|
||||
|
||||
export const mechanics_to_games = pgTable(
|
||||
'mechanics_to_games',
|
||||
{
|
||||
mechanic_id: uuid('mechanic_id')
|
||||
.notNull()
|
||||
.references(() => mechanics.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
game_id: uuid('game_id')
|
||||
.notNull()
|
||||
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
},
|
||||
(table) => {
|
||||
return {
|
||||
mechanicsToGamesPkey: primaryKey({
|
||||
columns: [table.mechanic_id, table.game_id],
|
||||
}),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const mechanics_to_games_relations = relations(mechanics_to_games, ({ one }) => ({
|
||||
mechanic: one(mechanics, {
|
||||
fields: [mechanics_to_games.mechanic_id],
|
||||
references: [mechanics.id],
|
||||
}),
|
||||
game: one(games, {
|
||||
fields: [mechanics_to_games.game_id],
|
||||
references: [games.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export const publishers_to_games = pgTable(
|
||||
'publishers_to_games',
|
||||
{
|
||||
publisher_id: uuid('publisher_id')
|
||||
.notNull()
|
||||
.references(() => publishers.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
game_id: uuid('game_id')
|
||||
.notNull()
|
||||
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||
},
|
||||
(table) => {
|
||||
return {
|
||||
publishersToGamesPkey: primaryKey({
|
||||
columns: [table.publisher_id, table.game_id],
|
||||
}),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const publishers_to_games_relations = relations(publishers_to_games, ({ one }) => ({
|
||||
publisher: one(publishers, {
|
||||
fields: [publishers_to_games.publisher_id],
|
||||
references: [publishers.id],
|
||||
}),
|
||||
game: one(games, {
|
||||
fields: [publishers_to_games.game_id],
|
||||
references: [games.id],
|
||||
}),
|
||||
}));
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
import { eq } from 'drizzle-orm';
|
||||
import db from '$lib/drizzle';
|
||||
import { roles, user_roles } from '../schema';
|
||||
import db from '../db';
|
||||
import { roles, user_roles } from '$db/schema';
|
||||
|
||||
export async function add_user_to_role(user_id: string, role_name: string, primary = false) {
|
||||
// Find the role by its name
|
||||
const role = await db.query.roles.findFirst({
|
||||
where: eq(roles.name, role_name)
|
||||
where: eq(roles.name, role_name),
|
||||
});
|
||||
|
||||
if (!role || !role.id) {
|
||||
|
|
@ -16,6 +16,6 @@ export async function add_user_to_role(user_id: string, role_name: string, prima
|
|||
return db.insert(user_roles).values({
|
||||
user_id,
|
||||
role_id: role.id,
|
||||
primary
|
||||
primary,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
import db from '$lib/drizzle';
|
||||
import db from '../db';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { users, type Users } from '../schema';
|
||||
import { users, type Users } from '$db/schema';
|
||||
import { add_user_to_role } from './roles';
|
||||
|
||||
export function create_user(user: Users) {
|
||||
return db.insert(users).values({
|
||||
username: user.username
|
||||
username: user.username,
|
||||
});
|
||||
}
|
||||
|
||||
export async function find_or_create_user(user: Users) {
|
||||
const existing_user = await db.query.users.findFirst({
|
||||
where: eq(users.username, user.username)
|
||||
where: eq(users.username, user.username),
|
||||
});
|
||||
if (existing_user) {
|
||||
return existing_user;
|
||||
|
|
@ -30,12 +30,12 @@ export async function find_user_with_roles(user_id: string) {
|
|||
with: {
|
||||
role: {
|
||||
select: {
|
||||
name: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!user_with_roles) {
|
||||
throw new Error('User not found');
|
||||
|
|
@ -43,6 +43,6 @@ export async function find_user_with_roles(user_id: string) {
|
|||
|
||||
return {
|
||||
...user_with_roles,
|
||||
roles: user_with_roles.role.map((user_role) => user_role.role.name)
|
||||
roles: user_with_roles.role.map((user_role) => user_role.role.name),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ const config = {
|
|||
inspector: {
|
||||
toggleKeyCombo: 'control-alt-shift',
|
||||
showToggleButton: 'always',
|
||||
toggleButtonPos: 'bottom-right'
|
||||
}
|
||||
toggleButtonPos: 'bottom-right',
|
||||
},
|
||||
},
|
||||
kit: {
|
||||
adapter: adapter(),
|
||||
|
|
@ -21,19 +21,20 @@ const config = {
|
|||
$assets: './src/assets',
|
||||
$components: './src/components',
|
||||
'$components/*': 'src/lib/components/*',
|
||||
$db: './src/db',
|
||||
$server: './src/server',
|
||||
$lib: './src/lib',
|
||||
$state: './src/state',
|
||||
$styles: './src/styles',
|
||||
$themes: './src/themes'
|
||||
}
|
||||
$themes: './src/themes',
|
||||
},
|
||||
},
|
||||
shadcn: {
|
||||
componentPath: './src/lib/components/ui'
|
||||
componentPath: './src/lib/components/ui',
|
||||
},
|
||||
compilerOptions: {
|
||||
enableSourcemap: true,
|
||||
}
|
||||
enableSourcemap: true,
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
|
|
|||
Loading…
Reference in a new issue