Fix: use intergers for discord ids

This commit is contained in:
Aron Malcher 2024-02-28 21:58:57 +01:00
parent ffaf8d989e
commit 95fee833a1
Signed by: aronmal
GPG key ID: 816B7707426FC612
9 changed files with 151 additions and 181 deletions

View file

@ -361,9 +361,8 @@
"required": ["guildId", "timezone", "features", "matches", "checksum"], "required": ["guildId", "timezone", "features", "matches", "checksum"],
"properties": { "properties": {
"guildId": { "guildId": {
"type": "string", "type": "number",
"format": "varchar(20)", "example": 1234567890123456789
"example": "1234567890123456789"
}, },
"timezone": { "timezone": {
"type": "string", "type": "string",
@ -389,9 +388,8 @@
"type": "boolean" "type": "boolean"
}, },
"channelId": { "channelId": {
"type": "string", "type": "number",
"format": "varchar(20)", "example": 1234567890123456789,
"example": "1234567890123456789",
"nullable": true "nullable": true
}, },
"targetMinute": { "targetMinute": {
@ -418,15 +416,13 @@
"type": "boolean" "type": "boolean"
}, },
"isAvailableRoleId": { "isAvailableRoleId": {
"type": "string", "type": "number",
"format": "varchar(20)", "example": 1234567890123456789,
"example": "1234567890123456789",
"nullable": true "nullable": true
}, },
"wantsToBeNotifieRoledId": { "wantsToBeNotifieRoledId": {
"type": "string", "type": "number",
"format": "varchar(20)", "example": 1234567890123456789,
"example": "1234567890123456789",
"nullable": true "nullable": true
} }
} }
@ -459,35 +455,31 @@
], ],
"properties": { "properties": {
"channelId": { "channelId": {
"type": "string", "type": "number",
"format": "varcharq(20)", "example": 1234567890123456789
"example": "1234567890123456789" },
"createrId": {
"type": "number",
"example": 1234567890123456789
},
"roleId": {
"type": "number",
"example": 1234567890123456789
},
"messageId": {
"type": "number",
"example": 1234567890123456789
}, },
"matchType": { "matchType": {
"type": "string", "type": "string",
"format": "varchar(50)", "format": "varchar(50)",
"example": "Scrim" "example": "Scrim"
}, },
"createrId": {
"type": "string",
"format": "varchar(20)",
"example": "1234567890123456789"
},
"roleId": {
"type": "string",
"format": "varchar(20)",
"example": "1234567890123456789"
},
"opponentName": { "opponentName": {
"type": "string", "type": "string",
"format": "varchar(100)", "format": "varchar(100)",
"example": "?" "example": "?"
}, },
"messageId": {
"type": "string",
"format": "varchar(20)",
"example": "1234567890123456789"
},
"utc_ts": { "utc_ts": {
"type": "string", "type": "string",
"example": "2020-01-01T00:00:00Z" "example": "2020-01-01T00:00:00Z"
@ -499,54 +491,46 @@
"required": ["channelId", "messageIds"], "required": ["channelId", "messageIds"],
"properties": { "properties": {
"channelId": { "channelId": {
"type": "string", "type": "number",
"format": "varchar(20)", "example": 1234567890123456789
"example": "1234567890123456789"
}, },
"messageIds": { "messageIds": {
"type": "object", "type": "object",
"required": ["0", "1", "2", "3", "4", "5", "6"], "required": ["0", "1", "2", "3", "4", "5", "6"],
"properties": { "properties": {
"0": { "0": {
"type": "string", "type": "number",
"format": "varchar(20)", "example": 1234567890123456789,
"example": "1234567890123456789",
"nullable": true "nullable": true
}, },
"1": { "1": {
"type": "string", "type": "number",
"format": "varchar(20)", "example": 1234567890123456789,
"example": "1234567890123456789",
"nullable": true "nullable": true
}, },
"2": { "2": {
"type": "string", "type": "number",
"format": "varchar(20)", "example": 1234567890123456789,
"example": "1234567890123456789",
"nullable": true "nullable": true
}, },
"3": { "3": {
"type": "string", "type": "number",
"format": "varchar(20)", "example": 1234567890123456789,
"example": "1234567890123456789",
"nullable": true "nullable": true
}, },
"4": { "4": {
"type": "string", "type": "number",
"format": "varchar(20)", "example": 1234567890123456789,
"example": "1234567890123456789",
"nullable": true "nullable": true
}, },
"5": { "5": {
"type": "string", "type": "number",
"format": "varchar(20)", "example": 1234567890123456789,
"example": "1234567890123456789",
"nullable": true "nullable": true
}, },
"6": { "6": {
"type": "string", "type": "number",
"format": "varchar(20)", "example": 1234567890123456789,
"example": "1234567890123456789",
"nullable": true "nullable": true
} }
} }

View file

@ -1,6 +1,7 @@
import { relations } from "drizzle-orm"; import { relations } from "drizzle-orm";
import { import {
boolean, boolean,
integer,
pgTable, pgTable,
primaryKey, primaryKey,
serial, serial,
@ -38,16 +39,14 @@ export const discordTokens = pgTable("tokens", {
}); });
export const guilds = pgTable("guilds", { export const guilds = pgTable("guilds", {
id: varchar("id", { length: 20 }).primaryKey(), id: integer("id").primaryKey(),
timezone: text("timezone").notNull().default("Etc/UTC"), timezone: text("timezone").notNull().default("Etc/UTC"),
tpEnabled: boolean("tp_enabled").notNull().default(false), tpEnabled: boolean("tp_enabled").notNull().default(false),
tpChannelId: varchar("tp_channel_id", { length: 20 }), tpChannelId: integer("tp_channel_id"),
tpInterval: smallint("target_interval").notNull(), tpInterval: smallint("target_interval").notNull(),
tpRoles: boolean("tp_roles").notNull(), tpRoles: boolean("tp_roles").notNull(),
isAvailableRoleId: varchar("is_available_role_id", { length: 20 }), isAvailableRoleId: integer("is_available_role_id"),
wantsToBeNotifieRoledId: varchar("wants_to_be_notified_role_id", { wantsToBeNotifieRoledId: integer("wants_to_be_notified_role_id"),
length: 20,
}),
}); });
export const guildsRelations = relations(guilds, ({ many }) => ({ export const guildsRelations = relations(guilds, ({ many }) => ({
@ -58,9 +57,9 @@ export const guildsRelations = relations(guilds, ({ many }) => ({
export const tpMessages = pgTable( export const tpMessages = pgTable(
"tp_messages", "tp_messages",
{ {
messageId: varchar("message_id", { length: 20 }), messageId: integer("message_id"),
day: smallint("day").notNull(), day: smallint("day").notNull(),
guildId: varchar("guild_id", { length: 20 }) guildId: integer("guild_id")
.notNull() .notNull()
.references(() => guilds.id, { onDelete: "cascade" }), .references(() => guilds.id, { onDelete: "cascade" }),
}, },
@ -80,14 +79,14 @@ export const tpMessagesRelations = relations(tpMessages, ({ one }) => ({
export const matches = pgTable("matches", { export const matches = pgTable("matches", {
id: serial("id").primaryKey(), id: serial("id").primaryKey(),
channelId: varchar("channel_id", { length: 20 }).notNull(), channelId: integer("channel_id").notNull(),
matchType: varchar("match_type", { length: 50 }).notNull(), matchType: varchar("match_type", { length: 50 }).notNull(),
createrId: varchar("creater_id", { length: 20 }).notNull(), createrId: integer("creater_id").notNull(),
roleId: varchar("role_id", { length: 20 }).notNull(), roleId: integer("role_id").notNull(),
opponentName: varchar("opponent_name", { length: 100 }).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(), utc_ts: timestamp("utc_ts").notNull(),
guildId: varchar("guild_id", { length: 20 }) guildId: integer("guild_id")
.notNull() .notNull()
.references(() => guilds.id, { onDelete: "cascade" }), .references(() => guilds.id, { onDelete: "cascade" }),
}); });

View file

@ -4,12 +4,12 @@ import objectHash from "object-hash";
export const buildMatches = ( export const buildMatches = (
matches: { matches: {
id: number; id: number;
messageId: string; messageId: number;
guildId: string; guildId: number;
channelId: string; channelId: number;
createrId: number;
roleId: number;
matchType: string; matchType: string;
createrId: string;
roleId: string;
opponentName: string; opponentName: string;
utc_ts: Date; utc_ts: Date;
}[], }[],
@ -23,27 +23,27 @@ export const buildMatches = (
); );
export function buildConfig(guildQuery: { export function buildConfig(guildQuery: {
id: string; id: number;
timezone: string; timezone: string;
tpEnabled: boolean; tpEnabled: boolean;
tpChannelId: string | null; tpChannelId: number | null;
tpInterval: number; tpInterval: number;
tpRoles: boolean; tpRoles: boolean;
isAvailableRoleId: string | null; isAvailableRoleId: number | null;
wantsToBeNotifieRoledId: string | null; wantsToBeNotifieRoledId: number | null;
tpMessages: { tpMessages: {
messageId: string | null; messageId: number | null;
day: number; day: number;
guildId: string; guildId: number;
}[]; }[];
matches: { matches: {
id: number; id: number;
messageId: string; messageId: number;
guildId: string; guildId: number;
channelId: string; channelId: number;
createrId: number;
roleId: number;
matchType: string; matchType: string;
createrId: string;
roleId: string;
opponentName: string; opponentName: string;
utc_ts: Date; utc_ts: Date;
}[]; }[];

View file

@ -3,7 +3,8 @@ import { z } from "zod";
export const zodId = z export const zodId = z
.string() .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({ export const zodTpMessages = z.object({
channelId: zodId, channelId: zodId,

View file

@ -22,15 +22,16 @@ export const GET = async (
return ErrorResponse("UNAUTHORIZED"); return ErrorResponse("UNAUTHORIZED");
} }
let guildId: number;
try { try {
zodId.parse(event.params.guildId); guildId = zodId.parse(event.params.guildId);
} catch (e) { } catch (e) {
return ErrorResponse("BAD_REQUEST", JSON.stringify(e)); return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
} }
const guildQuery = await db.query.guilds const guildQuery = await db.query.guilds
.findFirst({ .findFirst({
where: eq(guilds.id, event.params.guildId), where: eq(guilds.id, guildId),
with: { tpMessages: true, matches: true }, with: { tpMessages: true, matches: true },
}) })
.execute(); .execute();
@ -52,22 +53,23 @@ export const DELETE = async (
return ErrorResponse("UNAUTHORIZED"); return ErrorResponse("UNAUTHORIZED");
} }
let guildId: number;
try { try {
zodId.parse(event.params.guildId); guildId = zodId.parse(event.params.guildId);
} catch (e) { } catch (e) {
return ErrorResponse("BAD_REQUEST", JSON.stringify(e)); return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
} }
const guildQuery = await db.query.guilds const guildQuery = await db.query.guilds
.findFirst({ .findFirst({
where: eq(guilds.id, event.params.guildId), where: eq(guilds.id, guildId),
with: { tpMessages: true, matches: true }, with: { tpMessages: true, matches: true },
}) })
.execute(); .execute();
if (!guildQuery) return ErrorResponse("NOT_FOUND"); 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); return Res("NO_CONTENT", null);
}; };

View file

@ -5,7 +5,7 @@ import { guilds, matches } from "~/drizzle/schema";
import { BasicAuth } from "~/lib/auth"; import { BasicAuth } from "~/lib/auth";
import { buildMatches } from "~/lib/responseBuilders"; import { buildMatches } from "~/lib/responseBuilders";
import { ErrorResponse, Res } from "~/lib/responses"; import { ErrorResponse, Res } from "~/lib/responses";
import { zodMatch } from "~/lib/zod"; import { zodId, zodMatch } from "~/lib/zod";
import { APIResponse, RequestBody } from "~/types/backend"; import { APIResponse, RequestBody } from "~/types/backend";
type Path = "/api/{guildId}/matches"; type Path = "/api/{guildId}/matches";
@ -22,17 +22,22 @@ export const GET = async (
return ErrorResponse("UNAUTHORIZED"); 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 const guild = await db.query.guilds
.findFirst({ .findFirst({
where: eq(guilds.id, event.params.guildId), where: eq(guilds.id, guildId),
with: { with: {
matches: true, matches: true,
}, },
}) })
.execute(); .execute();
console.log(event.params.guildId, guild);
if (!guild) return ErrorResponse("NOT_FOUND"); if (!guild) return ErrorResponse("NOT_FOUND");
if (guild.matches.length < 1) return Res("NO_CONTENT", null); if (guild.matches.length < 1) return Res("NO_CONTENT", null);
@ -55,17 +60,22 @@ export const POST = async (
return ErrorResponse("UNAUTHORIZED"); 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 const guild = await db.query.guilds
.findFirst({ .findFirst({
where: eq(guilds.id, event.params.guildId), where: eq(guilds.id, guildId),
with: { with: {
matches: true, matches: true,
}, },
}) })
.execute(); .execute();
console.log(event.params.guildId, guild);
if (!guild) return ErrorResponse("NOT_FOUND"); if (!guild) return ErrorResponse("NOT_FOUND");
const unparsedBody = await new Response(event.request.body).json(); const unparsedBody = await new Response(event.request.body).json();

View file

@ -4,14 +4,14 @@ import db from "~/drizzle";
import { guilds, tpMessages } from "~/drizzle/schema"; import { guilds, tpMessages } from "~/drizzle/schema";
import { BasicAuth } from "~/lib/auth"; import { BasicAuth } from "~/lib/auth";
import { ErrorResponse, Res } from "~/lib/responses"; import { ErrorResponse, Res } from "~/lib/responses";
import { zodTpMessages } from "~/lib/zod"; import { zodId, zodTpMessages } from "~/lib/zod";
import { APIResponse, RequestBody } from "~/types/backend"; import { APIResponse, RequestBody } from "~/types/backend";
type Path = "/api/{guildId}/tp_messages"; type Path = "/api/{guildId}/tp_messages";
const DayKeys = ["0", "1", "2", "3", "4", "5", "6"] as const; const DayKeys = ["0", "1", "2", "3", "4", "5", "6"] as const;
type DayKeys = (typeof DayKeys)[number]; type DayKeys = (typeof DayKeys)[number];
type Messages = Record<DayKeys, string | null>; type Messages = Record<DayKeys, number | null>;
export const GET = async ( export const GET = async (
event: APIEvent, event: APIEvent,
@ -25,8 +25,15 @@ export const GET = async (
return ErrorResponse("UNAUTHORIZED"); 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({ const guild = await db.query.guilds.findFirst({
where: eq(guilds.id, event.params.guildId), where: eq(guilds.id, guildId),
with: { with: {
tpMessages: true, tpMessages: true,
}, },
@ -72,9 +79,16 @@ export const PUT = async (
return ErrorResponse("UNAUTHORIZED"); 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 const guild = await db.query.guilds
.findFirst({ .findFirst({
where: eq(guilds.id, event.params.guildId), where: eq(guilds.id, guildId),
with: { tpMessages: true }, with: { tpMessages: true },
}) })
.execute(); .execute();

View file

@ -5,6 +5,7 @@ import { guilds } from "~/drizzle/schema";
import { BasicAuth } from "~/lib/auth"; import { BasicAuth } from "~/lib/auth";
import { buildConfig } from "~/lib/responseBuilders"; import { buildConfig } from "~/lib/responseBuilders";
import { ErrorResponse, Res } from "~/lib/responses"; import { ErrorResponse, Res } from "~/lib/responses";
import { zodId } from "~/lib/zod";
import { APIResponse } from "~/types/backend"; import { APIResponse } from "~/types/backend";
type Path = "/api/boot"; type Path = "/api/boot";
@ -21,9 +22,16 @@ export const GET = async (
return ErrorResponse("UNAUTHORIZED"); 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 const guildQuery = await db.query.guilds
.findMany({ .findMany({
where: eq(guilds.id, event.params.guildId), where: eq(guilds.id, guildId),
with: { tpMessages: true, matches: true }, with: { tpMessages: true, matches: true },
}) })
.execute(); .execute();

112
src/types/liljudd.d.ts vendored
View file

@ -55,11 +55,8 @@ export type webhooks = Record<string, never>;
export interface components { export interface components {
schemas: { schemas: {
guildConfig: { guildConfig: {
/** /** @example 1234567890123456800 */
* Format: varchar(20) guildId: number;
* @example 1234567890123456789
*/
guildId: string;
/** /**
* Format: text * Format: text
* @example Europe/Berlin * @example Europe/Berlin
@ -68,11 +65,8 @@ export interface components {
features: { features: {
timePlanning: { timePlanning: {
enabled: boolean; enabled: boolean;
/** /** @example 1234567890123456800 */
* Format: varchar(20) channelId: number | null;
* @example 1234567890123456789
*/
channelId: string | null;
/** @example 0 */ /** @example 0 */
targetMinute: number; targetMinute: number;
/** @example 1 */ /** @example 1 */
@ -81,16 +75,10 @@ export interface components {
targetDay: number; targetDay: number;
roles: { roles: {
enabled: boolean; enabled: boolean;
/** /** @example 1234567890123456800 */
* Format: varchar(20) isAvailableRoleId: number | null;
* @example 1234567890123456789 /** @example 1234567890123456800 */
*/ wantsToBeNotifieRoledId: number | null;
isAvailableRoleId: string | null;
/**
* Format: varchar(20)
* @example 1234567890123456789
*/
wantsToBeNotifieRoledId: string | null;
}; };
}; };
}; };
@ -98,81 +86,45 @@ export interface components {
checksum: string; checksum: string;
}; };
match: { match: {
/** /** @example 1234567890123456800 */
* Format: varcharq(20) channelId: number;
* @example 1234567890123456789 /** @example 1234567890123456800 */
*/ createrId: number;
channelId: string; /** @example 1234567890123456800 */
roleId: number;
/** @example 1234567890123456800 */
messageId: number;
/** /**
* Format: varchar(50) * Format: varchar(50)
* @example Scrim * @example Scrim
*/ */
matchType: string; matchType: string;
/**
* Format: varchar(20)
* @example 1234567890123456789
*/
createrId: string;
/**
* Format: varchar(20)
* @example 1234567890123456789
*/
roleId: string;
/** /**
* Format: varchar(100) * Format: varchar(100)
* @example ? * @example ?
*/ */
opponentName: string; opponentName: string;
/**
* Format: varchar(20)
* @example 1234567890123456789
*/
messageId: string;
/** @example 2020-01-01T00:00:00Z */ /** @example 2020-01-01T00:00:00Z */
utc_ts: string; utc_ts: string;
}; };
tp_messages: { tp_messages: {
/** /** @example 1234567890123456800 */
* Format: varchar(20) channelId: number;
* @example 1234567890123456789
*/
channelId: string;
messageIds: { messageIds: {
/** /** @example 1234567890123456800 */
* Format: varchar(20) 0: number | null;
* @example 1234567890123456789 /** @example 1234567890123456800 */
*/ 1: number | null;
0: string | null; /** @example 1234567890123456800 */
/** 2: number | null;
* Format: varchar(20) /** @example 1234567890123456800 */
* @example 1234567890123456789 3: number | null;
*/ /** @example 1234567890123456800 */
1: string | null; 4: number | null;
/** /** @example 1234567890123456800 */
* Format: varchar(20) 5: number | null;
* @example 1234567890123456789 /** @example 1234567890123456800 */
*/ 6: number | null;
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;
}; };
}; };
}; };