From 95fee833a16d4993ffa9933792113bdfc8f2b989 Mon Sep 17 00:00:00 2001 From: aronmal Date: Wed, 28 Feb 2024 21:58:57 +0100 Subject: [PATCH] Fix: use intergers for discord ids --- public/api/specs/liljudd.json | 92 ++++++++----------- src/drizzle/schema.ts | 25 +++--- src/lib/responseBuilders.ts | 32 +++---- src/lib/zod.ts | 3 +- src/routes/api/[guildId]/config.ts | 12 +-- src/routes/api/[guildId]/matches.ts | 24 +++-- src/routes/api/[guildId]/tp_messages.ts | 22 ++++- src/routes/api/boot.ts | 10 ++- src/types/liljudd.d.ts | 112 +++++++----------------- 9 files changed, 151 insertions(+), 181 deletions(-) diff --git a/public/api/specs/liljudd.json b/public/api/specs/liljudd.json index aaa6295..2aaee56 100644 --- a/public/api/specs/liljudd.json +++ b/public/api/specs/liljudd.json @@ -361,9 +361,8 @@ "required": ["guildId", "timezone", "features", "matches", "checksum"], "properties": { "guildId": { - "type": "string", - "format": "varchar(20)", - "example": "1234567890123456789" + "type": "number", + "example": 1234567890123456789 }, "timezone": { "type": "string", @@ -389,9 +388,8 @@ "type": "boolean" }, "channelId": { - "type": "string", - "format": "varchar(20)", - "example": "1234567890123456789", + "type": "number", + "example": 1234567890123456789, "nullable": true }, "targetMinute": { @@ -418,15 +416,13 @@ "type": "boolean" }, "isAvailableRoleId": { - "type": "string", - "format": "varchar(20)", - "example": "1234567890123456789", + "type": "number", + "example": 1234567890123456789, "nullable": true }, "wantsToBeNotifieRoledId": { - "type": "string", - "format": "varchar(20)", - "example": "1234567890123456789", + "type": "number", + "example": 1234567890123456789, "nullable": true } } @@ -459,35 +455,31 @@ ], "properties": { "channelId": { - "type": "string", - "format": "varcharq(20)", - "example": "1234567890123456789" + "type": "number", + "example": 1234567890123456789 + }, + "createrId": { + "type": "number", + "example": 1234567890123456789 + }, + "roleId": { + "type": "number", + "example": 1234567890123456789 + }, + "messageId": { + "type": "number", + "example": 1234567890123456789 }, "matchType": { "type": "string", "format": "varchar(50)", "example": "Scrim" }, - "createrId": { - "type": "string", - "format": "varchar(20)", - "example": "1234567890123456789" - }, - "roleId": { - "type": "string", - "format": "varchar(20)", - "example": "1234567890123456789" - }, "opponentName": { "type": "string", "format": "varchar(100)", "example": "?" }, - "messageId": { - "type": "string", - "format": "varchar(20)", - "example": "1234567890123456789" - }, "utc_ts": { "type": "string", "example": "2020-01-01T00:00:00Z" @@ -499,54 +491,46 @@ "required": ["channelId", "messageIds"], "properties": { "channelId": { - "type": "string", - "format": "varchar(20)", - "example": "1234567890123456789" + "type": "number", + "example": 1234567890123456789 }, "messageIds": { "type": "object", "required": ["0", "1", "2", "3", "4", "5", "6"], "properties": { "0": { - "type": "string", - "format": "varchar(20)", - "example": "1234567890123456789", + "type": "number", + "example": 1234567890123456789, "nullable": true }, "1": { - "type": "string", - "format": "varchar(20)", - "example": "1234567890123456789", + "type": "number", + "example": 1234567890123456789, "nullable": true }, "2": { - "type": "string", - "format": "varchar(20)", - "example": "1234567890123456789", + "type": "number", + "example": 1234567890123456789, "nullable": true }, "3": { - "type": "string", - "format": "varchar(20)", - "example": "1234567890123456789", + "type": "number", + "example": 1234567890123456789, "nullable": true }, "4": { - "type": "string", - "format": "varchar(20)", - "example": "1234567890123456789", + "type": "number", + "example": 1234567890123456789, "nullable": true }, "5": { - "type": "string", - "format": "varchar(20)", - "example": "1234567890123456789", + "type": "number", + "example": 1234567890123456789, "nullable": true }, "6": { - "type": "string", - "format": "varchar(20)", - "example": "1234567890123456789", + "type": "number", + "example": 1234567890123456789, "nullable": true } } diff --git a/src/drizzle/schema.ts b/src/drizzle/schema.ts index 341e4c2..17d724b 100644 --- a/src/drizzle/schema.ts +++ b/src/drizzle/schema.ts @@ -1,6 +1,7 @@ import { relations } from "drizzle-orm"; import { boolean, + integer, pgTable, primaryKey, serial, @@ -38,16 +39,14 @@ export const discordTokens = pgTable("tokens", { }); export const guilds = pgTable("guilds", { - id: varchar("id", { length: 20 }).primaryKey(), + id: integer("id").primaryKey(), timezone: text("timezone").notNull().default("Etc/UTC"), tpEnabled: boolean("tp_enabled").notNull().default(false), - tpChannelId: varchar("tp_channel_id", { length: 20 }), + tpChannelId: integer("tp_channel_id"), tpInterval: smallint("target_interval").notNull(), tpRoles: boolean("tp_roles").notNull(), - isAvailableRoleId: varchar("is_available_role_id", { length: 20 }), - wantsToBeNotifieRoledId: varchar("wants_to_be_notified_role_id", { - length: 20, - }), + isAvailableRoleId: integer("is_available_role_id"), + wantsToBeNotifieRoledId: integer("wants_to_be_notified_role_id"), }); export const guildsRelations = relations(guilds, ({ many }) => ({ @@ -58,9 +57,9 @@ export const guildsRelations = relations(guilds, ({ many }) => ({ export const tpMessages = pgTable( "tp_messages", { - messageId: varchar("message_id", { length: 20 }), + messageId: integer("message_id"), day: smallint("day").notNull(), - guildId: varchar("guild_id", { length: 20 }) + guildId: integer("guild_id") .notNull() .references(() => guilds.id, { onDelete: "cascade" }), }, @@ -80,14 +79,14 @@ export const tpMessagesRelations = relations(tpMessages, ({ one }) => ({ export const matches = pgTable("matches", { id: serial("id").primaryKey(), - channelId: varchar("channel_id", { length: 20 }).notNull(), + channelId: integer("channel_id").notNull(), matchType: varchar("match_type", { length: 50 }).notNull(), - createrId: varchar("creater_id", { length: 20 }).notNull(), - roleId: varchar("role_id", { length: 20 }).notNull(), + createrId: integer("creater_id").notNull(), + roleId: integer("role_id").notNull(), opponentName: varchar("opponent_name", { length: 100 }).notNull(), - messageId: varchar("message_id", { length: 20 }).notNull(), + messageId: integer("message_id").notNull(), utc_ts: timestamp("utc_ts").notNull(), - guildId: varchar("guild_id", { length: 20 }) + guildId: integer("guild_id") .notNull() .references(() => guilds.id, { onDelete: "cascade" }), }); diff --git a/src/lib/responseBuilders.ts b/src/lib/responseBuilders.ts index ee58883..4bba2a8 100644 --- a/src/lib/responseBuilders.ts +++ b/src/lib/responseBuilders.ts @@ -4,12 +4,12 @@ import objectHash from "object-hash"; export const buildMatches = ( matches: { id: number; - messageId: string; - guildId: string; - channelId: string; + messageId: number; + guildId: number; + channelId: number; + createrId: number; + roleId: number; matchType: string; - createrId: string; - roleId: string; opponentName: string; utc_ts: Date; }[], @@ -23,27 +23,27 @@ export const buildMatches = ( ); export function buildConfig(guildQuery: { - id: string; + id: number; timezone: string; tpEnabled: boolean; - tpChannelId: string | null; + tpChannelId: number | null; tpInterval: number; tpRoles: boolean; - isAvailableRoleId: string | null; - wantsToBeNotifieRoledId: string | null; + isAvailableRoleId: number | null; + wantsToBeNotifieRoledId: number | null; tpMessages: { - messageId: string | null; + messageId: number | null; day: number; - guildId: string; + guildId: number; }[]; matches: { id: number; - messageId: string; - guildId: string; - channelId: string; + messageId: number; + guildId: number; + channelId: number; + createrId: number; + roleId: number; matchType: string; - createrId: string; - roleId: string; opponentName: string; utc_ts: Date; }[]; diff --git a/src/lib/zod.ts b/src/lib/zod.ts index b5810e1..17bfd68 100644 --- a/src/lib/zod.ts +++ b/src/lib/zod.ts @@ -3,7 +3,8 @@ import { z } from "zod"; export const zodId = z .string() - .refine((value) => /^\d{7,20}$/.test(value), "Invalid ID supplied"); + .refine((value) => /^\d{7,20}$/.test(value), "Invalid ID supplied") + .transform((value) => parseInt(value)); export const zodTpMessages = z.object({ channelId: zodId, diff --git a/src/routes/api/[guildId]/config.ts b/src/routes/api/[guildId]/config.ts index 9eb7816..6655999 100644 --- a/src/routes/api/[guildId]/config.ts +++ b/src/routes/api/[guildId]/config.ts @@ -22,15 +22,16 @@ export const GET = async ( return ErrorResponse("UNAUTHORIZED"); } + let guildId: number; try { - zodId.parse(event.params.guildId); + guildId = zodId.parse(event.params.guildId); } catch (e) { return ErrorResponse("BAD_REQUEST", JSON.stringify(e)); } const guildQuery = await db.query.guilds .findFirst({ - where: eq(guilds.id, event.params.guildId), + where: eq(guilds.id, guildId), with: { tpMessages: true, matches: true }, }) .execute(); @@ -52,22 +53,23 @@ export const DELETE = async ( return ErrorResponse("UNAUTHORIZED"); } + let guildId: number; try { - zodId.parse(event.params.guildId); + guildId = zodId.parse(event.params.guildId); } catch (e) { return ErrorResponse("BAD_REQUEST", JSON.stringify(e)); } const guildQuery = await db.query.guilds .findFirst({ - where: eq(guilds.id, event.params.guildId), + where: eq(guilds.id, guildId), with: { tpMessages: true, matches: true }, }) .execute(); if (!guildQuery) return ErrorResponse("NOT_FOUND"); - await db.delete(guilds).where(eq(guilds.id, event.params.guildId)).execute(); + await db.delete(guilds).where(eq(guilds.id, guildId)).execute(); return Res("NO_CONTENT", null); }; diff --git a/src/routes/api/[guildId]/matches.ts b/src/routes/api/[guildId]/matches.ts index 703654a..6ad4195 100644 --- a/src/routes/api/[guildId]/matches.ts +++ b/src/routes/api/[guildId]/matches.ts @@ -5,7 +5,7 @@ import { guilds, matches } from "~/drizzle/schema"; import { BasicAuth } from "~/lib/auth"; import { buildMatches } from "~/lib/responseBuilders"; import { ErrorResponse, Res } from "~/lib/responses"; -import { zodMatch } from "~/lib/zod"; +import { zodId, zodMatch } from "~/lib/zod"; import { APIResponse, RequestBody } from "~/types/backend"; type Path = "/api/{guildId}/matches"; @@ -22,17 +22,22 @@ export const GET = async ( return ErrorResponse("UNAUTHORIZED"); } + let guildId: number; + try { + guildId = zodId.parse(event.params.guildId); + } catch (e) { + return ErrorResponse("BAD_REQUEST", JSON.stringify(e)); + } + const guild = await db.query.guilds .findFirst({ - where: eq(guilds.id, event.params.guildId), + where: eq(guilds.id, guildId), with: { matches: true, }, }) .execute(); - console.log(event.params.guildId, guild); - if (!guild) return ErrorResponse("NOT_FOUND"); if (guild.matches.length < 1) return Res("NO_CONTENT", null); @@ -55,17 +60,22 @@ export const POST = async ( return ErrorResponse("UNAUTHORIZED"); } + let guildId: number; + try { + guildId = zodId.parse(event.params.guildId); + } catch (e) { + return ErrorResponse("BAD_REQUEST", JSON.stringify(e)); + } + const guild = await db.query.guilds .findFirst({ - where: eq(guilds.id, event.params.guildId), + where: eq(guilds.id, guildId), with: { matches: true, }, }) .execute(); - console.log(event.params.guildId, guild); - if (!guild) return ErrorResponse("NOT_FOUND"); const unparsedBody = await new Response(event.request.body).json(); diff --git a/src/routes/api/[guildId]/tp_messages.ts b/src/routes/api/[guildId]/tp_messages.ts index c4cb99a..043f63e 100644 --- a/src/routes/api/[guildId]/tp_messages.ts +++ b/src/routes/api/[guildId]/tp_messages.ts @@ -4,14 +4,14 @@ import db from "~/drizzle"; import { guilds, tpMessages } from "~/drizzle/schema"; import { BasicAuth } from "~/lib/auth"; import { ErrorResponse, Res } from "~/lib/responses"; -import { zodTpMessages } from "~/lib/zod"; +import { zodId, zodTpMessages } from "~/lib/zod"; import { APIResponse, RequestBody } from "~/types/backend"; type Path = "/api/{guildId}/tp_messages"; const DayKeys = ["0", "1", "2", "3", "4", "5", "6"] as const; type DayKeys = (typeof DayKeys)[number]; -type Messages = Record; +type Messages = Record; export const GET = async ( event: APIEvent, @@ -25,8 +25,15 @@ export const GET = async ( return ErrorResponse("UNAUTHORIZED"); } + let guildId: number; + try { + guildId = zodId.parse(event.params.guildId); + } catch (e) { + return ErrorResponse("BAD_REQUEST", JSON.stringify(e)); + } + const guild = await db.query.guilds.findFirst({ - where: eq(guilds.id, event.params.guildId), + where: eq(guilds.id, guildId), with: { tpMessages: true, }, @@ -72,9 +79,16 @@ export const PUT = async ( return ErrorResponse("UNAUTHORIZED"); } + let guildId: number; + try { + guildId = zodId.parse(event.params.guildId); + } catch (e) { + return ErrorResponse("BAD_REQUEST", JSON.stringify(e)); + } + const guild = await db.query.guilds .findFirst({ - where: eq(guilds.id, event.params.guildId), + where: eq(guilds.id, guildId), with: { tpMessages: true }, }) .execute(); diff --git a/src/routes/api/boot.ts b/src/routes/api/boot.ts index bad071c..26ef143 100644 --- a/src/routes/api/boot.ts +++ b/src/routes/api/boot.ts @@ -5,6 +5,7 @@ import { guilds } from "~/drizzle/schema"; import { BasicAuth } from "~/lib/auth"; import { buildConfig } from "~/lib/responseBuilders"; import { ErrorResponse, Res } from "~/lib/responses"; +import { zodId } from "~/lib/zod"; import { APIResponse } from "~/types/backend"; type Path = "/api/boot"; @@ -21,9 +22,16 @@ export const GET = async ( return ErrorResponse("UNAUTHORIZED"); } + let guildId: number; + try { + guildId = zodId.parse(event.params.guildId); + } catch (e) { + return ErrorResponse("BAD_REQUEST", JSON.stringify(e)); + } + const guildQuery = await db.query.guilds .findMany({ - where: eq(guilds.id, event.params.guildId), + where: eq(guilds.id, guildId), with: { tpMessages: true, matches: true }, }) .execute(); diff --git a/src/types/liljudd.d.ts b/src/types/liljudd.d.ts index 236c849..6e255b6 100644 --- a/src/types/liljudd.d.ts +++ b/src/types/liljudd.d.ts @@ -55,11 +55,8 @@ export type webhooks = Record; export interface components { schemas: { guildConfig: { - /** - * Format: varchar(20) - * @example 1234567890123456789 - */ - guildId: string; + /** @example 1234567890123456800 */ + guildId: number; /** * Format: text * @example Europe/Berlin @@ -68,11 +65,8 @@ export interface components { features: { timePlanning: { enabled: boolean; - /** - * Format: varchar(20) - * @example 1234567890123456789 - */ - channelId: string | null; + /** @example 1234567890123456800 */ + channelId: number | null; /** @example 0 */ targetMinute: number; /** @example 1 */ @@ -81,16 +75,10 @@ export interface components { targetDay: number; roles: { enabled: boolean; - /** - * Format: varchar(20) - * @example 1234567890123456789 - */ - isAvailableRoleId: string | null; - /** - * Format: varchar(20) - * @example 1234567890123456789 - */ - wantsToBeNotifieRoledId: string | null; + /** @example 1234567890123456800 */ + isAvailableRoleId: number | null; + /** @example 1234567890123456800 */ + wantsToBeNotifieRoledId: number | null; }; }; }; @@ -98,81 +86,45 @@ export interface components { checksum: string; }; match: { - /** - * Format: varcharq(20) - * @example 1234567890123456789 - */ - channelId: string; + /** @example 1234567890123456800 */ + channelId: number; + /** @example 1234567890123456800 */ + createrId: number; + /** @example 1234567890123456800 */ + roleId: number; + /** @example 1234567890123456800 */ + messageId: number; /** * Format: varchar(50) * @example Scrim */ matchType: string; - /** - * Format: varchar(20) - * @example 1234567890123456789 - */ - createrId: string; - /** - * Format: varchar(20) - * @example 1234567890123456789 - */ - roleId: string; /** * Format: varchar(100) * @example ? */ opponentName: string; - /** - * Format: varchar(20) - * @example 1234567890123456789 - */ - messageId: string; /** @example 2020-01-01T00:00:00Z */ utc_ts: string; }; tp_messages: { - /** - * Format: varchar(20) - * @example 1234567890123456789 - */ - channelId: string; + /** @example 1234567890123456800 */ + channelId: number; messageIds: { - /** - * Format: varchar(20) - * @example 1234567890123456789 - */ - 0: string | null; - /** - * Format: varchar(20) - * @example 1234567890123456789 - */ - 1: string | null; - /** - * Format: varchar(20) - * @example 1234567890123456789 - */ - 2: string | null; - /** - * Format: varchar(20) - * @example 1234567890123456789 - */ - 3: string | null; - /** - * Format: varchar(20) - * @example 1234567890123456789 - */ - 4: string | null; - /** - * Format: varchar(20) - * @example 1234567890123456789 - */ - 5: string | null; - /** - * Format: varchar(20) - * @example 1234567890123456789 - */ - 6: string | null; + /** @example 1234567890123456800 */ + 0: number | null; + /** @example 1234567890123456800 */ + 1: number | null; + /** @example 1234567890123456800 */ + 2: number | null; + /** @example 1234567890123456800 */ + 3: number | null; + /** @example 1234567890123456800 */ + 4: number | null; + /** @example 1234567890123456800 */ + 5: number | null; + /** @example 1234567890123456800 */ + 6: number | null; }; }; };