Fix: Using bigint and added backend testing
This commit is contained in:
parent
ed6195e1e2
commit
89507f8412
20 changed files with 830 additions and 292 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
src/drizzle/migrations
|
src/drizzle/migrations
|
||||||
|
log
|
||||||
|
|
||||||
dist
|
dist
|
||||||
.vinxi
|
.vinxi
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
GET https://discord.com/api/users/@me
|
|
||||||
Authorization: Bearer {{$dotenv DISCORD_ACCESS_TOKEN}}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET https://discord.com/api/users/@me
|
|
||||||
Authorization: Bot {{$dotenv DISCORD_BOT_TOKEN}}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET https://discord.com/api/users/@me/guilds
|
|
||||||
Authorization: Bearer {{$dotenv DISCORD_ACCESS_TOKEN}}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET https://discord.com/api/users/@me/guilds/{{$dotenv DISCORD_GUILD_ID}}/member
|
|
||||||
Authorization: Bearer {{$dotenv DISCORD_ACCESS_TOKEN}}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET https://discord.com/api/guilds/{{$dotenv DISCORD_GUILD_ID}}
|
|
||||||
Authorization: Bot {{$dotenv DISCORD_BOT_TOKEN}}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
POST https://discord.com/api/oauth2/token/revoke
|
|
||||||
Content-Type: application/x-www-form-urlencoded
|
|
||||||
Authorization: Basic {{$dotenv DISCORD_CLIENT_ID}}:{{$dotenv DISCORD_CLIENT_SECRET}}
|
|
||||||
|
|
||||||
token={{$dotenv DISCORD_ACCESS_TOKEN}}&token_type_hint=access_token
|
|
166
e2e/auth.spec.ts
166
e2e/auth.spec.ts
|
@ -1,14 +1,18 @@
|
||||||
|
import { DrizzlePostgreSQLAdapter } from "@lucia-auth/adapter-drizzle";
|
||||||
import { createId } from "@paralleldrive/cuid2";
|
import { createId } from "@paralleldrive/cuid2";
|
||||||
import { expect, test, type BrowserContext, type Page } from "@playwright/test";
|
import { expect, test, type BrowserContext, type Page } from "@playwright/test";
|
||||||
|
import "dotenv/config";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import { drizzle } from "drizzle-orm/postgres-js";
|
||||||
import { Lucia, type Cookie } from "lucia";
|
import { Lucia, type Cookie } from "lucia";
|
||||||
import createClient from "openapi-fetch";
|
import createClient from "openapi-fetch";
|
||||||
import * as schema from "~/drizzle/schema";
|
|
||||||
import { paths } from "~/types/discord";
|
|
||||||
|
|
||||||
import { DrizzlePostgreSQLAdapter } from "@lucia-auth/adapter-drizzle";
|
|
||||||
import "dotenv/config";
|
|
||||||
import { drizzle } from "drizzle-orm/postgres-js";
|
|
||||||
import postgres from "postgres";
|
import postgres from "postgres";
|
||||||
|
import * as schema from "~/drizzle/schema";
|
||||||
|
import type * as discord from "~/types/discord";
|
||||||
|
import type * as liljudd from "~/types/liljudd";
|
||||||
|
|
||||||
|
const unencoded = `${process.env.DISCORD_CLIENT_ID}:${process.env.DISCORD_CLIENT_SECRET}`;
|
||||||
|
const encoded = btoa(unencoded);
|
||||||
|
|
||||||
const queryClient = postgres(process.env.DATABASE_URL!);
|
const queryClient = postgres(process.env.DATABASE_URL!);
|
||||||
const db = drizzle(queryClient, {
|
const db = drizzle(queryClient, {
|
||||||
|
@ -25,7 +29,22 @@ let page: Page;
|
||||||
|
|
||||||
let sessionCookie: Cookie | undefined;
|
let sessionCookie: Cookie | undefined;
|
||||||
|
|
||||||
|
let userId = createId();
|
||||||
|
let guildId: bigint;
|
||||||
|
|
||||||
test.describe.serial("User auth process", () => {
|
test.describe.serial("User auth process", () => {
|
||||||
|
test.beforeAll(() => {
|
||||||
|
expect(
|
||||||
|
[
|
||||||
|
"DISCORD_CLIENT_ID",
|
||||||
|
"DISCORD_CLIENT_SECRET",
|
||||||
|
"DATABASE_URL",
|
||||||
|
"DISCORD_BOT_TOKEN",
|
||||||
|
].filter((e) => typeof process.env[e] === "undefined").length,
|
||||||
|
{ message: "Please specify all env vars." },
|
||||||
|
).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
test.beforeAll(async ({ browser }) => {
|
test.beforeAll(async ({ browser }) => {
|
||||||
context = await browser.newContext();
|
context = await browser.newContext();
|
||||||
page = await context.newPage();
|
page = await context.newPage();
|
||||||
|
@ -59,6 +78,14 @@ test.describe.serial("User auth process", () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test.afterAll("Delete DB entries", async () => {
|
||||||
|
await db.delete(schema.users).where(eq(schema.users.id, userId)).execute();
|
||||||
|
await db
|
||||||
|
.delete(schema.guilds)
|
||||||
|
.where(eq(schema.guilds.id, guildId))
|
||||||
|
.execute();
|
||||||
|
});
|
||||||
|
|
||||||
test.afterAll(async () => {
|
test.afterAll(async () => {
|
||||||
await context.close();
|
await context.close();
|
||||||
});
|
});
|
||||||
|
@ -75,8 +102,8 @@ test.describe.serial("User auth process", () => {
|
||||||
await page.waitForURL("/");
|
await page.waitForURL("/");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Generate auth session for further tests", async () => {
|
test("Generate auth session for further tests", async ({ browser }) => {
|
||||||
const { GET } = createClient<paths>({
|
const { GET } = createClient<discord.paths>({
|
||||||
baseUrl: "https://discord.com/api/v10",
|
baseUrl: "https://discord.com/api/v10",
|
||||||
});
|
});
|
||||||
const discordUserResponse = await GET("/users/@me", {
|
const discordUserResponse = await GET("/users/@me", {
|
||||||
|
@ -86,7 +113,22 @@ test.describe.serial("User auth process", () => {
|
||||||
});
|
});
|
||||||
if (discordUserResponse.error) throw discordUserResponse.error;
|
if (discordUserResponse.error) throw discordUserResponse.error;
|
||||||
const discordUser = discordUserResponse.data;
|
const discordUser = discordUserResponse.data;
|
||||||
const userId = createId();
|
|
||||||
|
const browserName = browser.browserType().name() as
|
||||||
|
| "chromium"
|
||||||
|
| "webkit"
|
||||||
|
| "firefox";
|
||||||
|
|
||||||
|
userId = discordUser.id + userId.slice(discordUser.id.length);
|
||||||
|
userId = userId.slice(0, -browserName.length) + browserName;
|
||||||
|
|
||||||
|
enum BrowserIds {
|
||||||
|
chromium,
|
||||||
|
webkit,
|
||||||
|
firefox,
|
||||||
|
}
|
||||||
|
guildId = BigInt(discordUser.id) ^ BigInt(BrowserIds[browserName]);
|
||||||
|
|
||||||
await db.insert(schema.users).values({
|
await db.insert(schema.users).values({
|
||||||
id: userId,
|
id: userId,
|
||||||
discord_id: discordUser.id,
|
discord_id: discordUser.id,
|
||||||
|
@ -119,4 +161,110 @@ test.describe.serial("User auth process", () => {
|
||||||
"landing_page_logged_in.png",
|
"landing_page_logged_in.png",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Test Api", async () => {
|
||||||
|
const { GET, POST, PUT } = createClient<liljudd.paths>({
|
||||||
|
baseUrl: "http://localhost:3000/",
|
||||||
|
});
|
||||||
|
|
||||||
|
const createConfigResponse = await POST("/api/{guildId}/config", {
|
||||||
|
params: {
|
||||||
|
path: {
|
||||||
|
guildId: guildId.toString(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
Authorization: `Basic ${encoded}`,
|
||||||
|
Origin: "http://localhost:3000",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (createConfigResponse.error)
|
||||||
|
throw new Error(createConfigResponse.error.error);
|
||||||
|
|
||||||
|
let getConfigResponse = await GET("/api/{guildId}/config", {
|
||||||
|
params: {
|
||||||
|
path: {
|
||||||
|
guildId: guildId.toString(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
Authorization: `Basic ${encoded}`,
|
||||||
|
Origin: "http://localhost:3000",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (getConfigResponse.error) throw new Error(getConfigResponse.error.error);
|
||||||
|
|
||||||
|
switch (getConfigResponse.data?.checksum) {
|
||||||
|
case "209a644c31a5ef123c432c2885d231a2e0efc4de": // chromium
|
||||||
|
case "aead21e132a94ab897ec28e0f0c337a66207bad3": // webkit
|
||||||
|
case "c3e2ff2ce5a8936234552125a54c2fe1ce1a35da": // firefox
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
"Before guild GET checksum didn't matched known ones: " +
|
||||||
|
getConfigResponse.data?.checksum,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const putTimePlanningResponse = await PUT("/api/{guildId}/timePlanning", {
|
||||||
|
body: {
|
||||||
|
enabled: true,
|
||||||
|
channelId: "1234567890123456789",
|
||||||
|
rolesEnabled: true,
|
||||||
|
isAvailableRoleId: "1234567890123456789",
|
||||||
|
wantsToBeNotifieRoledId: "1234567890123456789",
|
||||||
|
messageIds: {
|
||||||
|
"0": "1234567890123456789",
|
||||||
|
"1": "1234567890123456789",
|
||||||
|
"2": "1234567890123456789",
|
||||||
|
"3": "1234567890123456789",
|
||||||
|
"4": "1234567890123456789",
|
||||||
|
"5": "1234567890123456789",
|
||||||
|
"6": "1234567890123456789",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
path: {
|
||||||
|
guildId: guildId.toString(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
Authorization: `Basic ${encoded}`,
|
||||||
|
Origin: "http://localhost:3000",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (putTimePlanningResponse.error)
|
||||||
|
throw new Error(putTimePlanningResponse.error.error);
|
||||||
|
|
||||||
|
getConfigResponse = await GET("/api/{guildId}/config", {
|
||||||
|
params: {
|
||||||
|
path: {
|
||||||
|
guildId: guildId.toString(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
Authorization: `Basic ${encoded}`,
|
||||||
|
Origin: "http://localhost:3000",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (getConfigResponse.error) throw new Error(getConfigResponse.error.error);
|
||||||
|
|
||||||
|
switch (getConfigResponse.data?.checksum) {
|
||||||
|
case "681c8324b21096255d942bb78bd6655da90d352e": // chromium
|
||||||
|
case "a2fb3601b7d0949b1ceada3b3ac0ba408c6159bb": // webkit
|
||||||
|
case "bf20daba95e8f3ddd17cc64e8a7ba184b68ad37b": // firefox
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
"After guild GET checksum didn't matched known ones: " +
|
||||||
|
getConfigResponse.data?.checksum,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
"@solidjs/router": "^0.12.4",
|
"@solidjs/router": "^0.12.4",
|
||||||
"@solidjs/start": "^0.6.0",
|
"@solidjs/start": "^0.6.0",
|
||||||
"arctic": "^1.2.1",
|
"arctic": "^1.2.1",
|
||||||
|
"colors": "^1.4.0",
|
||||||
"drizzle-orm": "^0.29.4",
|
"drizzle-orm": "^0.29.4",
|
||||||
"http-status": "^1.7.4",
|
"http-status": "^1.7.4",
|
||||||
"json-stable-stringify": "^1.1.1",
|
"json-stable-stringify": "^1.1.1",
|
||||||
|
|
|
@ -44,6 +44,9 @@ dependencies:
|
||||||
arctic:
|
arctic:
|
||||||
specifier: ^1.2.1
|
specifier: ^1.2.1
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
|
colors:
|
||||||
|
specifier: ^1.4.0
|
||||||
|
version: 1.4.0
|
||||||
drizzle-orm:
|
drizzle-orm:
|
||||||
specifier: ^0.29.4
|
specifier: ^0.29.4
|
||||||
version: 0.29.4(pg@8.11.3)(postgres@3.4.3)
|
version: 0.29.4(pg@8.11.3)(postgres@3.4.3)
|
||||||
|
@ -2761,6 +2764,11 @@ packages:
|
||||||
resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
|
resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/colors@1.4.0:
|
||||||
|
resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==}
|
||||||
|
engines: {node: '>=0.1.90'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/commander@2.20.3:
|
/commander@2.20.3:
|
||||||
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
|
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -3370,6 +3378,7 @@ packages:
|
||||||
|
|
||||||
/eslint-config-prettier@9.1.0(eslint@8.57.0):
|
/eslint-config-prettier@9.1.0(eslint@8.57.0):
|
||||||
resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==}
|
resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==}
|
||||||
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: '>=7.0.0'
|
eslint: '>=7.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -4671,6 +4680,7 @@ packages:
|
||||||
/nitropack@2.8.1:
|
/nitropack@2.8.1:
|
||||||
resolution: {integrity: sha512-pODv2kEEzZSDQR+1UMXbGyNgMedUDq/qUomtiAnQKQvLy52VGlecXO1xDfH3i0kP1yKEcKTnWsx1TAF5gHM7xQ==}
|
resolution: {integrity: sha512-pODv2kEEzZSDQR+1UMXbGyNgMedUDq/qUomtiAnQKQvLy52VGlecXO1xDfH3i0kP1yKEcKTnWsx1TAF5gHM7xQ==}
|
||||||
engines: {node: ^16.11.0 || >=17.0.0}
|
engines: {node: ^16.11.0 || >=17.0.0}
|
||||||
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
xml2js: ^0.6.2
|
xml2js: ^0.6.2
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
|
@ -5344,6 +5354,7 @@ packages:
|
||||||
/rollup-plugin-visualizer@5.12.0(rollup@4.12.0):
|
/rollup-plugin-visualizer@5.12.0(rollup@4.12.0):
|
||||||
resolution: {integrity: sha512-8/NU9jXcHRs7Nnj07PF2o4gjxmm9lXIrZ8r175bT9dK8qoLlvKTwRMArRCMgpMGlq8CTLugRvEmyMeMXIU2pNQ==}
|
resolution: {integrity: sha512-8/NU9jXcHRs7Nnj07PF2o4gjxmm9lXIrZ8r175bT9dK8qoLlvKTwRMArRCMgpMGlq8CTLugRvEmyMeMXIU2pNQ==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
rollup: 2.x || 3.x || 4.x
|
rollup: 2.x || 3.x || 4.x
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
|
@ -6048,6 +6059,7 @@ packages:
|
||||||
|
|
||||||
/update-browserslist-db@1.0.13(browserslist@4.23.0):
|
/update-browserslist-db@1.0.13(browserslist@4.23.0):
|
||||||
resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
|
resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
|
||||||
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
browserslist: '>= 4.21.0'
|
browserslist: '>= 4.21.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -6265,6 +6277,7 @@ packages:
|
||||||
/vite@5.1.1(@types/node@20.11.22)(sass@1.71.1):
|
/vite@5.1.1(@types/node@20.11.22)(sass@1.71.1):
|
||||||
resolution: {integrity: sha512-wclpAgY3F1tR7t9LL5CcHC41YPkQIpKUGeIuT8MdNwNZr6OqOTLs7JX5vIHAtzqLWXts0T+GDrh9pN2arneKqg==}
|
resolution: {integrity: sha512-wclpAgY3F1tR7t9LL5CcHC41YPkQIpKUGeIuT8MdNwNZr6OqOTLs7JX5vIHAtzqLWXts0T+GDrh9pN2arneKqg==}
|
||||||
engines: {node: ^18.0.0 || >=20.0.0}
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@types/node': ^18.0.0 || >=20.0.0
|
'@types/node': ^18.0.0 || >=20.0.0
|
||||||
less: '*'
|
less: '*'
|
||||||
|
|
|
@ -31,13 +31,34 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
"description": "Invalid ID supplied"
|
"description": "Invalid ID supplied",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"401": {
|
"401": {
|
||||||
"description": "Unauthorized"
|
"description": "Unauthorized",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"description": "Guild not found"
|
"description": "Guild not found",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -77,13 +98,92 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
"description": "Invalid ID supplied"
|
"description": "Invalid ID supplied",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"401": {
|
"401": {
|
||||||
"description": "Unauthorized"
|
"description": "Unauthorized",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"description": "Guild not found"
|
"description": "Guild not found",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"basicAuth": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"tags": ["Guild config"],
|
||||||
|
"summary": "Creates a guild's config by ID",
|
||||||
|
"description": "Create a guild's config when the bot is has joined a new guild.",
|
||||||
|
"operationId": "postGuildById",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "guildId",
|
||||||
|
"in": "path",
|
||||||
|
"description": "ID of guild's config to create",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "varchar(20)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "successful operation"
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Invalid ID supplied",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Guild not found",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -101,7 +201,7 @@
|
||||||
{
|
{
|
||||||
"name": "guildId",
|
"name": "guildId",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"description": "ID of guild config to delete",
|
"description": "ID of guild's config to delete",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -114,13 +214,34 @@
|
||||||
"description": "successful operation"
|
"description": "successful operation"
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
"description": "Invalid ID supplied"
|
"description": "Invalid ID supplied",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"401": {
|
"401": {
|
||||||
"description": "Unauthorized"
|
"description": "Unauthorized",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"description": "Guild not found"
|
"description": "Guild not found",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -130,17 +251,17 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/{guildId}/tp_messages": {
|
"/api/{guildId}/timePlanning": {
|
||||||
"get": {
|
"get": {
|
||||||
"tags": ["Time planning messages"],
|
"tags": ["Time planning messages"],
|
||||||
"summary": "Find the tp_messages of guild by ID",
|
"summary": "Find the timePlanning of guild by ID",
|
||||||
"description": "Returns tp_messages for a guild",
|
"description": "Returns timePlanning for a guild",
|
||||||
"operationId": "getTp_messagesOfGuildById",
|
"operationId": "gettimePlanningOfGuildById",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"name": "guildId",
|
"name": "guildId",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"description": "ID of guild's tp_messages to return",
|
"description": "ID of guild's timePlanning to return",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -154,22 +275,40 @@
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/schemas/tp_messages"
|
"$ref": "#/components/schemas/timePlanning"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"204": {
|
|
||||||
"description": "Time planning not enabled for this guild"
|
|
||||||
},
|
|
||||||
"400": {
|
"400": {
|
||||||
"description": "Invalid ID supplied"
|
"description": "Invalid ID supplied",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"401": {
|
"401": {
|
||||||
"description": "Unauthorized"
|
"description": "Unauthorized",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"description": "Guild not found"
|
"description": "Guild not found",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -180,14 +319,14 @@
|
||||||
},
|
},
|
||||||
"put": {
|
"put": {
|
||||||
"tags": ["Time planning messages"],
|
"tags": ["Time planning messages"],
|
||||||
"summary": "Put new message IDs for tp_messages of guild by ID",
|
"summary": "Put new message IDs for timePlanning of guild by ID",
|
||||||
"description": "Returns tp_messages for a guild",
|
"description": "Returns timePlanning for a guild",
|
||||||
"operationId": "putTp_messagesOfGuildById",
|
"operationId": "puttimePlanningOfGuildById",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"name": "guildId",
|
"name": "guildId",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"description": "ID of guild's tp_messages to return",
|
"description": "ID of guild's timePlanning to return",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -196,11 +335,11 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"requestBody": {
|
"requestBody": {
|
||||||
"description": "Put new message IDs for tp_messages in channel",
|
"description": "Put new message IDs for timePlanning in channel",
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/schemas/tp_messages"
|
"$ref": "#/components/schemas/timePlanning"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -211,16 +350,34 @@
|
||||||
"description": "successful operation"
|
"description": "successful operation"
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
"description": "Invalid ID supplied"
|
"description": "Invalid ID supplied",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"401": {
|
"401": {
|
||||||
"description": "Unauthorized"
|
"description": "Unauthorized",
|
||||||
},
|
"content": {
|
||||||
"403": {
|
"application/json": {
|
||||||
"description": "Time planning not enabled for this guild"
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"description": "Guild not found"
|
"description": "Guild not found",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -234,13 +391,13 @@
|
||||||
"get": {
|
"get": {
|
||||||
"tags": ["Matches"],
|
"tags": ["Matches"],
|
||||||
"summary": "Find all matches of guild by ID",
|
"summary": "Find all matches of guild by ID",
|
||||||
"description": "Returns tp_messages for a guild",
|
"description": "Returns timePlanning for a guild",
|
||||||
"operationId": "getMatchesOfGuildById",
|
"operationId": "getMatchesOfGuildById",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"name": "guildId",
|
"name": "guildId",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"description": "ID of guild's tp_messages to return",
|
"description": "ID of guild's timePlanning to return",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -273,17 +430,35 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"204": {
|
|
||||||
"description": "Time planning not enabled for this guild"
|
|
||||||
},
|
|
||||||
"400": {
|
"400": {
|
||||||
"description": "Invalid ID supplied"
|
"description": "Invalid ID supplied",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"401": {
|
"401": {
|
||||||
"description": "Unauthorized"
|
"description": "Unauthorized",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"description": "Guild not found"
|
"description": "Guild not found",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -295,7 +470,7 @@
|
||||||
"post": {
|
"post": {
|
||||||
"tags": ["Matches"],
|
"tags": ["Matches"],
|
||||||
"summary": "Save a new created match of guild by ID",
|
"summary": "Save a new created match of guild by ID",
|
||||||
"description": "Returns tp_messages for a guild",
|
"description": "Returns timePlanning for a guild",
|
||||||
"operationId": "postMatchOfGuildById",
|
"operationId": "postMatchOfGuildById",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
|
@ -337,13 +512,34 @@
|
||||||
"description": "successful operation"
|
"description": "successful operation"
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
"description": "Invalid ID supplied"
|
"description": "Invalid ID supplied",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"401": {
|
"401": {
|
||||||
"description": "Unauthorized"
|
"description": "Unauthorized",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"description": "Guild not found"
|
"description": "Guild not found",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -361,8 +557,7 @@
|
||||||
"required": ["guildId", "timezone", "features", "matches", "checksum"],
|
"required": ["guildId", "timezone", "features", "matches", "checksum"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"guildId": {
|
"guildId": {
|
||||||
"type": "number",
|
"$ref": "#/components/schemas/id"
|
||||||
"example": 1234567890123456789
|
|
||||||
},
|
},
|
||||||
"timezone": {
|
"timezone": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -388,9 +583,7 @@
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"channelId": {
|
"channelId": {
|
||||||
"type": "number",
|
"$ref": "#/components/schemas/idOrNull"
|
||||||
"example": 1234567890123456789,
|
|
||||||
"nullable": true
|
|
||||||
},
|
},
|
||||||
"targetMinute": {
|
"targetMinute": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
|
@ -416,14 +609,10 @@
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"isAvailableRoleId": {
|
"isAvailableRoleId": {
|
||||||
"type": "number",
|
"$ref": "#/components/schemas/idOrNull"
|
||||||
"example": 1234567890123456789,
|
|
||||||
"nullable": true
|
|
||||||
},
|
},
|
||||||
"wantsToBeNotifieRoledId": {
|
"wantsToBeNotifieRoledId": {
|
||||||
"type": "number",
|
"$ref": "#/components/schemas/idOrNull"
|
||||||
"example": 1234567890123456789,
|
|
||||||
"nullable": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -455,20 +644,16 @@
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"channelId": {
|
"channelId": {
|
||||||
"type": "number",
|
"$ref": "#/components/schemas/id"
|
||||||
"example": 1234567890123456789
|
|
||||||
},
|
},
|
||||||
"createrId": {
|
"createrId": {
|
||||||
"type": "number",
|
"$ref": "#/components/schemas/id"
|
||||||
"example": 1234567890123456789
|
|
||||||
},
|
},
|
||||||
"roleId": {
|
"roleId": {
|
||||||
"type": "number",
|
"$ref": "#/components/schemas/id"
|
||||||
"example": 1234567890123456789
|
|
||||||
},
|
},
|
||||||
"messageId": {
|
"messageId": {
|
||||||
"type": "number",
|
"$ref": "#/components/schemas/id"
|
||||||
"example": 1234567890123456789
|
|
||||||
},
|
},
|
||||||
"matchType": {
|
"matchType": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -486,54 +671,78 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tp_messages": {
|
"timePlanning": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["channelId", "messageIds"],
|
"required": [
|
||||||
|
"enabled",
|
||||||
|
"channelId",
|
||||||
|
"rolesEnabled",
|
||||||
|
"isAvailableRoleId",
|
||||||
|
"wantsToBeNotifieRoledId",
|
||||||
|
"messageIds"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"channelId": {
|
"channelId": {
|
||||||
"type": "number",
|
"$ref": "#/components/schemas/idOrNull"
|
||||||
"example": 1234567890123456789
|
},
|
||||||
|
"rolesEnabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"isAvailableRoleId": {
|
||||||
|
"$ref": "#/components/schemas/idOrNull"
|
||||||
|
},
|
||||||
|
"wantsToBeNotifieRoledId": {
|
||||||
|
"$ref": "#/components/schemas/idOrNull"
|
||||||
},
|
},
|
||||||
"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": "number",
|
"$ref": "#/components/schemas/idOrNull"
|
||||||
"example": 1234567890123456789,
|
|
||||||
"nullable": true
|
|
||||||
},
|
},
|
||||||
"1": {
|
"1": {
|
||||||
"type": "number",
|
"$ref": "#/components/schemas/idOrNull"
|
||||||
"example": 1234567890123456789,
|
|
||||||
"nullable": true
|
|
||||||
},
|
},
|
||||||
"2": {
|
"2": {
|
||||||
"type": "number",
|
"$ref": "#/components/schemas/idOrNull"
|
||||||
"example": 1234567890123456789,
|
|
||||||
"nullable": true
|
|
||||||
},
|
},
|
||||||
"3": {
|
"3": {
|
||||||
"type": "number",
|
"$ref": "#/components/schemas/idOrNull"
|
||||||
"example": 1234567890123456789,
|
|
||||||
"nullable": true
|
|
||||||
},
|
},
|
||||||
"4": {
|
"4": {
|
||||||
"type": "number",
|
"$ref": "#/components/schemas/idOrNull"
|
||||||
"example": 1234567890123456789,
|
|
||||||
"nullable": true
|
|
||||||
},
|
},
|
||||||
"5": {
|
"5": {
|
||||||
"type": "number",
|
"$ref": "#/components/schemas/idOrNull"
|
||||||
"example": 1234567890123456789,
|
|
||||||
"nullable": true
|
|
||||||
},
|
},
|
||||||
"6": {
|
"6": {
|
||||||
"type": "number",
|
"$ref": "#/components/schemas/idOrNull"
|
||||||
"example": 1234567890123456789,
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^\\d{7,20}$",
|
||||||
|
"example": "1234567890123456789"
|
||||||
|
},
|
||||||
|
"idOrNull": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^\\d{7,20}$",
|
||||||
|
"example": "1234567890123456789",
|
||||||
"nullable": true
|
"nullable": true
|
||||||
}
|
},
|
||||||
}
|
"error": {
|
||||||
|
"type": "object",
|
||||||
|
"required": "error",
|
||||||
|
"properties": {
|
||||||
|
"error": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { relations } from "drizzle-orm";
|
import { relations } from "drizzle-orm";
|
||||||
import {
|
import {
|
||||||
|
bigint,
|
||||||
boolean,
|
boolean,
|
||||||
integer,
|
|
||||||
pgTable,
|
pgTable,
|
||||||
primaryKey,
|
primaryKey,
|
||||||
serial,
|
serial,
|
||||||
|
@ -39,14 +39,16 @@ export const discordTokens = pgTable("tokens", {
|
||||||
});
|
});
|
||||||
|
|
||||||
export const guilds = pgTable("guilds", {
|
export const guilds = pgTable("guilds", {
|
||||||
id: integer("id").primaryKey(),
|
id: bigint("id", { mode: "bigint" }).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: integer("tp_channel_id"),
|
tpChannelId: bigint("tp_channel_id", { mode: "bigint" }),
|
||||||
tpInterval: smallint("target_interval").notNull(),
|
tpInterval: smallint("target_interval").notNull().default(64),
|
||||||
tpRoles: boolean("tp_roles").notNull(),
|
tpRolesEnabled: boolean("tp_roles_enabled").notNull().default(false),
|
||||||
isAvailableRoleId: integer("is_available_role_id"),
|
isAvailableRoleId: bigint("is_available_role_id", { mode: "bigint" }),
|
||||||
wantsToBeNotifieRoledId: integer("wants_to_be_notified_role_id"),
|
wantsToBeNotifieRoledId: bigint("wants_to_be_notified_role_id", {
|
||||||
|
mode: "bigint",
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const guildsRelations = relations(guilds, ({ many }) => ({
|
export const guildsRelations = relations(guilds, ({ many }) => ({
|
||||||
|
@ -57,9 +59,9 @@ export const guildsRelations = relations(guilds, ({ many }) => ({
|
||||||
export const tpMessages = pgTable(
|
export const tpMessages = pgTable(
|
||||||
"tp_messages",
|
"tp_messages",
|
||||||
{
|
{
|
||||||
messageId: integer("message_id"),
|
messageId: bigint("message_id", { mode: "bigint" }),
|
||||||
day: smallint("day").notNull(),
|
day: smallint("day").notNull(),
|
||||||
guildId: integer("guild_id")
|
guildId: bigint("guild_id", { mode: "bigint" })
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => guilds.id, { onDelete: "cascade" }),
|
.references(() => guilds.id, { onDelete: "cascade" }),
|
||||||
},
|
},
|
||||||
|
@ -79,14 +81,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: integer("channel_id").notNull(),
|
channelId: bigint("channel_id", { mode: "bigint" }).notNull(),
|
||||||
matchType: varchar("match_type", { length: 50 }).notNull(),
|
matchType: varchar("match_type", { length: 50 }).notNull(),
|
||||||
createrId: integer("creater_id").notNull(),
|
createrId: bigint("creater_id", { mode: "bigint" }).notNull(),
|
||||||
roleId: integer("role_id").notNull(),
|
roleId: bigint("role_id", { mode: "bigint" }).notNull(),
|
||||||
opponentName: varchar("opponent_name", { length: 100 }).notNull(),
|
opponentName: varchar("opponent_name", { length: 100 }).notNull(),
|
||||||
messageId: integer("message_id").notNull(),
|
messageId: bigint("message_id", { mode: "bigint" }).notNull(),
|
||||||
utc_ts: timestamp("utc_ts").notNull(),
|
utc_ts: timestamp("utc_ts").notNull(),
|
||||||
guildId: integer("guild_id")
|
guildId: bigint("guild_id", { mode: "bigint" })
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => guilds.id, { onDelete: "cascade" }),
|
.references(() => guilds.id, { onDelete: "cascade" }),
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,14 +2,27 @@ import stringify from "json-stable-stringify";
|
||||||
import objectHash from "object-hash";
|
import objectHash from "object-hash";
|
||||||
import { guilds, matches, tpMessages } from "~/drizzle/schema";
|
import { guilds, matches, tpMessages } from "~/drizzle/schema";
|
||||||
import { ExtractDataTypes, GetColumns } from "~/types/db";
|
import { ExtractDataTypes, GetColumns } from "~/types/db";
|
||||||
|
import { components } from "~/types/liljudd";
|
||||||
|
|
||||||
export const buildMatches = (
|
export const buildMatches = (
|
||||||
queryMatches: ExtractDataTypes<GetColumns<typeof matches>>[],
|
queryMatches: ExtractDataTypes<GetColumns<typeof matches>>[],
|
||||||
) =>
|
): components["schemas"]["match"][] =>
|
||||||
queryMatches.map(
|
queryMatches.map(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
({
|
||||||
({ id, guildId, utc_ts, ...match }) => ({
|
channelId,
|
||||||
...match,
|
createrId,
|
||||||
|
roleId,
|
||||||
|
messageId,
|
||||||
|
matchType,
|
||||||
|
opponentName,
|
||||||
|
utc_ts,
|
||||||
|
}) => ({
|
||||||
|
channelId: channelId.toString(),
|
||||||
|
createrId: createrId.toString(),
|
||||||
|
roleId: roleId.toString(),
|
||||||
|
messageId: messageId.toString(),
|
||||||
|
matchType,
|
||||||
|
opponentName,
|
||||||
utc_ts: utc_ts.toISOString(),
|
utc_ts: utc_ts.toISOString(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -19,14 +32,14 @@ export function buildConfig(
|
||||||
tpMessages: ExtractDataTypes<GetColumns<typeof tpMessages>>[];
|
tpMessages: ExtractDataTypes<GetColumns<typeof tpMessages>>[];
|
||||||
matches: ExtractDataTypes<GetColumns<typeof matches>>[];
|
matches: ExtractDataTypes<GetColumns<typeof matches>>[];
|
||||||
},
|
},
|
||||||
) {
|
): components["schemas"]["guildConfig"] {
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
timezone,
|
timezone,
|
||||||
tpEnabled,
|
tpEnabled,
|
||||||
tpChannelId,
|
tpChannelId,
|
||||||
tpInterval,
|
tpInterval,
|
||||||
tpRoles,
|
tpRolesEnabled: tpRoles,
|
||||||
isAvailableRoleId,
|
isAvailableRoleId,
|
||||||
wantsToBeNotifieRoledId,
|
wantsToBeNotifieRoledId,
|
||||||
} = guildQuery;
|
} = guildQuery;
|
||||||
|
@ -36,20 +49,26 @@ export function buildConfig(
|
||||||
const targetDay = (tpInterval >> 11) & 7;
|
const targetDay = (tpInterval >> 11) & 7;
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
guildId: id,
|
guildId: id.toString(),
|
||||||
timezone,
|
timezone,
|
||||||
features: {
|
features: {
|
||||||
timePlanning: {
|
timePlanning: {
|
||||||
enabled: tpEnabled,
|
enabled: tpEnabled,
|
||||||
channelId: tpChannelId,
|
channelId: tpChannelId?.toString() ?? null,
|
||||||
targetMinute,
|
targetMinute,
|
||||||
targetHour,
|
targetHour,
|
||||||
targetDay,
|
targetDay,
|
||||||
roles: { enabled: tpRoles, isAvailableRoleId, wantsToBeNotifieRoledId },
|
roles: {
|
||||||
|
enabled: tpRoles,
|
||||||
|
isAvailableRoleId: isAvailableRoleId?.toString() ?? null,
|
||||||
|
wantsToBeNotifieRoledId: wantsToBeNotifieRoledId?.toString() ?? null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
matches: buildMatches(guildQuery.matches),
|
matches: buildMatches(guildQuery.matches),
|
||||||
checksum: objectHash(stringify(guildQuery)),
|
|
||||||
};
|
};
|
||||||
return payload;
|
|
||||||
|
// generate checksum from payload because
|
||||||
|
// from guildQuery results in bigint serialization error
|
||||||
|
return { ...payload, checksum: objectHash(stringify(payload)) };
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ export function ErrorResponse<
|
||||||
M extends Methods<P>,
|
M extends Methods<P>,
|
||||||
C extends StatusCodes<P, M> = StatusCodes<P, M>,
|
C extends StatusCodes<P, M> = StatusCodes<P, M>,
|
||||||
>(code: C, error?: string): APIResponse<P, M> {
|
>(code: C, error?: string): APIResponse<P, M> {
|
||||||
|
console.log(code, error);
|
||||||
const responseData = {
|
const responseData = {
|
||||||
error: error ?? httpStatus[`${httpStatus[code]}_NAME`],
|
error: error ?? httpStatus[`${httpStatus[code]}_NAME`],
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const zodId = z
|
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 zodBigIntId = zodId.transform((value) => BigInt(value));
|
||||||
|
|
||||||
export const zodTpMessages = z.object({
|
export const zodTpMessages = z.object({
|
||||||
channelId: zodId,
|
enabled: z.boolean(),
|
||||||
|
channelId: zodId.nullable(),
|
||||||
|
rolesEnabled: z.boolean(),
|
||||||
|
isAvailableRoleId: zodId.nullable(),
|
||||||
|
wantsToBeNotifieRoledId: zodId.nullable(),
|
||||||
messageIds: z.object({
|
messageIds: z.object({
|
||||||
"0": zodId.nullable(),
|
"0": zodId.nullable(),
|
||||||
"1": zodId.nullable(),
|
"1": zodId.nullable(),
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
import { createMiddleware } from "@solidjs/start/middleware";
|
import { createMiddleware } from "@solidjs/start/middleware";
|
||||||
import { Session, User, verifyRequestOrigin } from "lucia";
|
import colors from "colors";
|
||||||
|
import fs from "fs";
|
||||||
|
import { verifyRequestOrigin } from "lucia";
|
||||||
import { appendHeader, getCookie, getHeader } from "vinxi/http";
|
import { appendHeader, getCookie, getHeader } from "vinxi/http";
|
||||||
import { lucia } from "./lib/auth";
|
import { lucia } from "./lib/auth";
|
||||||
|
|
||||||
|
colors.enable();
|
||||||
|
|
||||||
|
let started: boolean = false;
|
||||||
|
|
||||||
export default createMiddleware({
|
export default createMiddleware({
|
||||||
onRequest: async (event) => {
|
onRequest: async (event) => {
|
||||||
if (event.nativeEvent.node.req.method !== "GET") {
|
if (event.nativeEvent.node.req.method !== "GET") {
|
||||||
|
@ -43,12 +49,52 @@ export default createMiddleware({
|
||||||
event.nativeEvent.context.session = session;
|
event.nativeEvent.context.session = session;
|
||||||
event.nativeEvent.context.user = user;
|
event.nativeEvent.context.user = user;
|
||||||
},
|
},
|
||||||
});
|
onBeforeResponse: async (event, response) => {
|
||||||
|
let consoleLog = "",
|
||||||
|
fileLog = "";
|
||||||
|
|
||||||
declare module "h3" {
|
if (!started) {
|
||||||
// eslint-disable-next-line no-unused-vars
|
try {
|
||||||
interface H3EventContext {
|
await fs.promises.mkdir("log");
|
||||||
user: User | null;
|
console.log("Created 'log' Folder.");
|
||||||
session: Session | null;
|
} catch {}
|
||||||
}
|
started = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentDate = new Date();
|
||||||
|
const year = currentDate.getFullYear();
|
||||||
|
const month = String(currentDate.getMonth() + 1).padStart(2, "0");
|
||||||
|
const day = String(currentDate.getDate()).padStart(2, "0");
|
||||||
|
const hours = String(currentDate.getHours()).padStart(2, "0");
|
||||||
|
const minutes = String(currentDate.getMinutes()).padStart(2, "0");
|
||||||
|
const seconds = String(currentDate.getSeconds()).padStart(2, "0");
|
||||||
|
|
||||||
|
// Create a short and numeric representation
|
||||||
|
const date = `[${year}-${month}-${day}_${hours}:${minutes}:${seconds}]`;
|
||||||
|
const xForwardedFor = event.request.headers.get("x-forwarded-for");
|
||||||
|
const ip = (xForwardedFor || "127.0.0.1, 192.168.178.1").split(",");
|
||||||
|
const route = event.request.url;
|
||||||
|
const frontend = !new URL(event.request.url).pathname.startsWith("/api");
|
||||||
|
const method = frontend ? "Frontend" : event.request.method;
|
||||||
|
const code =
|
||||||
|
(response.body as Response | undefined)?.status ?? event.response.status;
|
||||||
|
consoleLog += [
|
||||||
|
date,
|
||||||
|
ip[0].yellow,
|
||||||
|
method,
|
||||||
|
code,
|
||||||
|
route?.green,
|
||||||
|
event.nativeEvent.context.user?.discord_id.rainbow,
|
||||||
|
].join(" ");
|
||||||
|
fileLog += [
|
||||||
|
date,
|
||||||
|
ip[0],
|
||||||
|
method,
|
||||||
|
code,
|
||||||
|
route,
|
||||||
|
event.nativeEvent.context.user?.discord_id,
|
||||||
|
].join(" ");
|
||||||
|
await fs.promises.appendFile("log/log.txt", fileLog + "\n");
|
||||||
|
console.log(consoleLog);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
@ -5,7 +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 { zodBigIntId } from "~/lib/zod";
|
||||||
import { APIResponse } from "~/types/backend";
|
import { APIResponse } from "~/types/backend";
|
||||||
|
|
||||||
type Path = "/api/{guildId}/config";
|
type Path = "/api/{guildId}/config";
|
||||||
|
@ -22,9 +22,9 @@ export const GET = async (
|
||||||
return ErrorResponse("UNAUTHORIZED");
|
return ErrorResponse("UNAUTHORIZED");
|
||||||
}
|
}
|
||||||
|
|
||||||
let guildId: number;
|
let guildId: bigint;
|
||||||
try {
|
try {
|
||||||
guildId = zodId.parse(event.params.guildId);
|
guildId = zodBigIntId.parse(event.params.guildId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,32 @@ export const GET = async (
|
||||||
return Res("OK", buildConfig(guildQuery));
|
return Res("OK", buildConfig(guildQuery));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
event: APIEvent,
|
||||||
|
): Promise<APIResponse<Path, "post">> => {
|
||||||
|
switch (event.request.headers.get("authorization")) {
|
||||||
|
case BasicAuth.unencoded:
|
||||||
|
case BasicAuth.encoded:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ErrorResponse("UNAUTHORIZED");
|
||||||
|
}
|
||||||
|
|
||||||
|
let guildId: bigint;
|
||||||
|
try {
|
||||||
|
guildId = zodBigIntId.parse(event.params.guildId);
|
||||||
|
} catch (e) {
|
||||||
|
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
const guildQuery = await db.insert(guilds).values({ id: guildId }).execute();
|
||||||
|
|
||||||
|
if (!guildQuery) return ErrorResponse("NOT_FOUND");
|
||||||
|
|
||||||
|
return Res("NO_CONTENT", null);
|
||||||
|
};
|
||||||
|
|
||||||
export const DELETE = async (
|
export const DELETE = async (
|
||||||
event: APIEvent,
|
event: APIEvent,
|
||||||
): Promise<APIResponse<Path, "delete">> => {
|
): Promise<APIResponse<Path, "delete">> => {
|
||||||
|
@ -53,9 +79,9 @@ export const DELETE = async (
|
||||||
return ErrorResponse("UNAUTHORIZED");
|
return ErrorResponse("UNAUTHORIZED");
|
||||||
}
|
}
|
||||||
|
|
||||||
let guildId: number;
|
let guildId: bigint;
|
||||||
try {
|
try {
|
||||||
guildId = zodId.parse(event.params.guildId);
|
guildId = zodBigIntId.parse(event.params.guildId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 { zodId, zodMatch } from "~/lib/zod";
|
import { zodBigIntId, 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,9 +22,9 @@ export const GET = async (
|
||||||
return ErrorResponse("UNAUTHORIZED");
|
return ErrorResponse("UNAUTHORIZED");
|
||||||
}
|
}
|
||||||
|
|
||||||
let guildId: number;
|
let guildId: bigint;
|
||||||
try {
|
try {
|
||||||
guildId = zodId.parse(event.params.guildId);
|
guildId = zodBigIntId.parse(event.params.guildId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
||||||
}
|
}
|
||||||
|
@ -60,9 +60,9 @@ export const POST = async (
|
||||||
return ErrorResponse("UNAUTHORIZED");
|
return ErrorResponse("UNAUTHORIZED");
|
||||||
}
|
}
|
||||||
|
|
||||||
let guildId: number;
|
let guildId: bigint;
|
||||||
try {
|
try {
|
||||||
guildId = zodId.parse(event.params.guildId);
|
guildId = zodBigIntId.parse(event.params.guildId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
||||||
}
|
}
|
||||||
|
@ -94,8 +94,13 @@ export const POST = async (
|
||||||
);
|
);
|
||||||
|
|
||||||
await db.insert(matches).values({
|
await db.insert(matches).values({
|
||||||
...body.match,
|
|
||||||
guildId: guild.id,
|
guildId: guild.id,
|
||||||
|
channelId: BigInt(body.match.channelId),
|
||||||
|
roleId: BigInt(body.match.roleId),
|
||||||
|
createrId: BigInt(body.match.createrId),
|
||||||
|
messageId: BigInt(body.match.messageId),
|
||||||
|
matchType: body.match.matchType,
|
||||||
|
opponentName: body.match.opponentName,
|
||||||
utc_ts: new Date(body.match.utc_ts),
|
utc_ts: new Date(body.match.utc_ts),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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 { zodId, zodTpMessages } from "~/lib/zod";
|
import { zodBigIntId, 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}/timePlanning";
|
||||||
|
|
||||||
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, number | null>;
|
type Messages = Record<DayKeys, string | null>;
|
||||||
|
|
||||||
export const GET = async (
|
export const GET = async (
|
||||||
event: APIEvent,
|
event: APIEvent,
|
||||||
|
@ -25,9 +25,9 @@ export const GET = async (
|
||||||
return ErrorResponse("UNAUTHORIZED");
|
return ErrorResponse("UNAUTHORIZED");
|
||||||
}
|
}
|
||||||
|
|
||||||
let guildId: number;
|
let guildId: bigint;
|
||||||
try {
|
try {
|
||||||
guildId = zodId.parse(event.params.guildId);
|
guildId = zodBigIntId.parse(event.params.guildId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
||||||
}
|
}
|
||||||
|
@ -41,13 +41,11 @@ export const GET = async (
|
||||||
|
|
||||||
if (!guild) return ErrorResponse("NOT_FOUND");
|
if (!guild) return ErrorResponse("NOT_FOUND");
|
||||||
|
|
||||||
if (!guild.tpEnabled || !guild.tpChannelId) return Res("NO_CONTENT", null);
|
|
||||||
|
|
||||||
const tpMessages = guild.tpMessages.reduce(
|
const tpMessages = guild.tpMessages.reduce(
|
||||||
(acc, message) => {
|
(acc, message) => {
|
||||||
const day = message.day.toString() as DayKeys;
|
const day = message.day.toString() as DayKeys;
|
||||||
if (!/^[0-6]$/.test(day)) return acc;
|
if (!/^[0-6]$/.test(day)) return acc;
|
||||||
acc[day] = message.messageId;
|
acc[day] = message.messageId?.toString() ?? null;
|
||||||
return acc;
|
return acc;
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -62,7 +60,11 @@ export const GET = async (
|
||||||
);
|
);
|
||||||
|
|
||||||
return Res("OK", {
|
return Res("OK", {
|
||||||
channelId: guild.tpChannelId,
|
enabled: guild.tpEnabled,
|
||||||
|
channelId: guild.tpChannelId?.toString() ?? null,
|
||||||
|
rolesEnabled: guild.tpRolesEnabled,
|
||||||
|
isAvailableRoleId: guild.isAvailableRoleId?.toString() ?? null,
|
||||||
|
wantsToBeNotifieRoledId: guild.wantsToBeNotifieRoledId?.toString() ?? null,
|
||||||
messageIds: tpMessages,
|
messageIds: tpMessages,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -79,9 +81,9 @@ export const PUT = async (
|
||||||
return ErrorResponse("UNAUTHORIZED");
|
return ErrorResponse("UNAUTHORIZED");
|
||||||
}
|
}
|
||||||
|
|
||||||
let guildId: number;
|
let guildId: bigint;
|
||||||
try {
|
try {
|
||||||
guildId = zodId.parse(event.params.guildId);
|
guildId = zodBigIntId.parse(event.params.guildId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
||||||
}
|
}
|
||||||
|
@ -95,8 +97,6 @@ export const PUT = async (
|
||||||
|
|
||||||
if (!guild) return ErrorResponse("NOT_FOUND");
|
if (!guild) return ErrorResponse("NOT_FOUND");
|
||||||
|
|
||||||
if (!guild.tpEnabled) return ErrorResponse("FORBIDDEN");
|
|
||||||
|
|
||||||
const unparsedBody = await new Response(event.request.body).json();
|
const unparsedBody = await new Response(event.request.body).json();
|
||||||
|
|
||||||
let body: RequestBody<Path, "put">;
|
let body: RequestBody<Path, "put">;
|
||||||
|
@ -106,19 +106,36 @@ export const PUT = async (
|
||||||
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (guild.tpChannelId !== body.channelId)
|
const {
|
||||||
|
enabled,
|
||||||
|
channelId,
|
||||||
|
rolesEnabled,
|
||||||
|
isAvailableRoleId,
|
||||||
|
wantsToBeNotifieRoledId,
|
||||||
|
messageIds,
|
||||||
|
} = body;
|
||||||
|
if (guild.tpChannelId !== channelId)
|
||||||
await db
|
await db
|
||||||
.update(guilds)
|
.update(guilds)
|
||||||
.set({ tpChannelId: body.channelId })
|
.set({
|
||||||
|
tpEnabled: enabled,
|
||||||
|
tpChannelId: channelId ? BigInt(channelId) : null,
|
||||||
|
tpRolesEnabled: rolesEnabled,
|
||||||
|
isAvailableRoleId: isAvailableRoleId ? BigInt(isAvailableRoleId) : null,
|
||||||
|
wantsToBeNotifieRoledId: wantsToBeNotifieRoledId
|
||||||
|
? BigInt(wantsToBeNotifieRoledId)
|
||||||
|
: null,
|
||||||
|
})
|
||||||
.where(eq(guilds.id, guild.id))
|
.where(eq(guilds.id, guild.id))
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
DayKeys.map(async (dayStr) => {
|
DayKeys.map(async (dayStr) => {
|
||||||
const day = parseInt(dayStr);
|
const day = parseInt(dayStr);
|
||||||
|
const messageId = messageIds[dayStr];
|
||||||
await db
|
await db
|
||||||
.update(tpMessages)
|
.update(tpMessages)
|
||||||
.set({ messageId: body.messageIds[dayStr] })
|
.set({ messageId: messageId ? BigInt(messageId) : null })
|
||||||
.where(and(eq(tpMessages.guildId, guild.id), eq(tpMessages.day, day)))
|
.where(and(eq(tpMessages.guildId, guild.id), eq(tpMessages.day, day)))
|
||||||
.execute();
|
.execute();
|
||||||
}),
|
}),
|
|
@ -5,7 +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 { zodBigIntId } from "~/lib/zod";
|
||||||
import { APIResponse } from "~/types/backend";
|
import { APIResponse } from "~/types/backend";
|
||||||
|
|
||||||
type Path = "/api/boot";
|
type Path = "/api/boot";
|
||||||
|
@ -22,9 +22,9 @@ export const GET = async (
|
||||||
return ErrorResponse("UNAUTHORIZED");
|
return ErrorResponse("UNAUTHORIZED");
|
||||||
}
|
}
|
||||||
|
|
||||||
let guildId: number;
|
let guildId: bigint;
|
||||||
try {
|
try {
|
||||||
guildId = zodId.parse(event.params.guildId);
|
guildId = zodBigIntId.parse(event.params.guildId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
||||||
}
|
}
|
||||||
|
|
2
src/types/db.d.ts
vendored
2
src/types/db.d.ts
vendored
|
@ -6,6 +6,8 @@ export type GetColumns<T> =
|
||||||
export type ExtractDataTypes<T> = {
|
export type ExtractDataTypes<T> = {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
[K in keyof T]: T[K] extends PgColumn<infer ColumnConfig, any, any>
|
[K in keyof T]: T[K] extends PgColumn<infer ColumnConfig, any, any>
|
||||||
|
? ColumnConfig["notNull"] extends true
|
||||||
? ColumnConfig["data"]
|
? ColumnConfig["data"]
|
||||||
|
: ColumnConfig["data"] | null
|
||||||
: unknown;
|
: unknown;
|
||||||
};
|
};
|
||||||
|
|
1
src/types/env.d.ts
vendored
1
src/types/env.d.ts
vendored
|
@ -12,7 +12,6 @@ interface ImportMetaEnv {
|
||||||
readonly VITE_DATABASE_URL: string;
|
readonly VITE_DATABASE_URL: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
interface ImportMeta {
|
interface ImportMeta {
|
||||||
readonly env: ImportMetaEnv;
|
readonly env: ImportMetaEnv;
|
||||||
}
|
}
|
||||||
|
|
242
src/types/liljudd.d.ts
vendored
242
src/types/liljudd.d.ts
vendored
|
@ -18,33 +18,38 @@ export interface paths {
|
||||||
* @description Returns a single guild's config.
|
* @description Returns a single guild's config.
|
||||||
*/
|
*/
|
||||||
get: operations["getGuildById"];
|
get: operations["getGuildById"];
|
||||||
|
/**
|
||||||
|
* Creates a guild's config by ID
|
||||||
|
* @description Create a guild's config when the bot is has joined a new guild.
|
||||||
|
*/
|
||||||
|
post: operations["postGuildById"];
|
||||||
/**
|
/**
|
||||||
* Deletes a guild's config by ID
|
* Deletes a guild's config by ID
|
||||||
* @description Delete a guild's config when the bot is removed from the guild.
|
* @description Delete a guild's config when the bot is removed from the guild.
|
||||||
*/
|
*/
|
||||||
delete: operations["deleteGuildById"];
|
delete: operations["deleteGuildById"];
|
||||||
};
|
};
|
||||||
"/api/{guildId}/tp_messages": {
|
"/api/{guildId}/timePlanning": {
|
||||||
/**
|
/**
|
||||||
* Find the tp_messages of guild by ID
|
* Find the timePlanning of guild by ID
|
||||||
* @description Returns tp_messages for a guild
|
* @description Returns timePlanning for a guild
|
||||||
*/
|
*/
|
||||||
get: operations["getTp_messagesOfGuildById"];
|
get: operations["gettimePlanningOfGuildById"];
|
||||||
/**
|
/**
|
||||||
* Put new message IDs for tp_messages of guild by ID
|
* Put new message IDs for timePlanning of guild by ID
|
||||||
* @description Returns tp_messages for a guild
|
* @description Returns timePlanning for a guild
|
||||||
*/
|
*/
|
||||||
put: operations["putTp_messagesOfGuildById"];
|
put: operations["puttimePlanningOfGuildById"];
|
||||||
};
|
};
|
||||||
"/api/{guildId}/matches": {
|
"/api/{guildId}/matches": {
|
||||||
/**
|
/**
|
||||||
* Find all matches of guild by ID
|
* Find all matches of guild by ID
|
||||||
* @description Returns tp_messages for a guild
|
* @description Returns timePlanning for a guild
|
||||||
*/
|
*/
|
||||||
get: operations["getMatchesOfGuildById"];
|
get: operations["getMatchesOfGuildById"];
|
||||||
/**
|
/**
|
||||||
* Save a new created match of guild by ID
|
* Save a new created match of guild by ID
|
||||||
* @description Returns tp_messages for a guild
|
* @description Returns timePlanning for a guild
|
||||||
*/
|
*/
|
||||||
post: operations["postMatchOfGuildById"];
|
post: operations["postMatchOfGuildById"];
|
||||||
};
|
};
|
||||||
|
@ -55,8 +60,7 @@ export type webhooks = Record<string, never>;
|
||||||
export interface components {
|
export interface components {
|
||||||
schemas: {
|
schemas: {
|
||||||
guildConfig: {
|
guildConfig: {
|
||||||
/** @example 1234567890123456800 */
|
guildId: components["schemas"]["id"];
|
||||||
guildId: number;
|
|
||||||
/**
|
/**
|
||||||
* Format: text
|
* Format: text
|
||||||
* @example Europe/Berlin
|
* @example Europe/Berlin
|
||||||
|
@ -65,8 +69,7 @@ export interface components {
|
||||||
features: {
|
features: {
|
||||||
timePlanning: {
|
timePlanning: {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
/** @example 1234567890123456800 */
|
channelId: components["schemas"]["idOrNull"];
|
||||||
channelId: number | null;
|
|
||||||
/** @example 0 */
|
/** @example 0 */
|
||||||
targetMinute: number;
|
targetMinute: number;
|
||||||
/** @example 1 */
|
/** @example 1 */
|
||||||
|
@ -75,10 +78,8 @@ export interface components {
|
||||||
targetDay: number;
|
targetDay: number;
|
||||||
roles: {
|
roles: {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
/** @example 1234567890123456800 */
|
isAvailableRoleId: components["schemas"]["idOrNull"];
|
||||||
isAvailableRoleId: number | null;
|
wantsToBeNotifieRoledId: components["schemas"]["idOrNull"];
|
||||||
/** @example 1234567890123456800 */
|
|
||||||
wantsToBeNotifieRoledId: number | null;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -86,14 +87,10 @@ export interface components {
|
||||||
checksum: string;
|
checksum: string;
|
||||||
};
|
};
|
||||||
match: {
|
match: {
|
||||||
/** @example 1234567890123456800 */
|
channelId: components["schemas"]["id"];
|
||||||
channelId: number;
|
createrId: components["schemas"]["id"];
|
||||||
/** @example 1234567890123456800 */
|
roleId: components["schemas"]["id"];
|
||||||
createrId: number;
|
messageId: components["schemas"]["id"];
|
||||||
/** @example 1234567890123456800 */
|
|
||||||
roleId: number;
|
|
||||||
/** @example 1234567890123456800 */
|
|
||||||
messageId: number;
|
|
||||||
/**
|
/**
|
||||||
* Format: varchar(50)
|
* Format: varchar(50)
|
||||||
* @example Scrim
|
* @example Scrim
|
||||||
|
@ -107,26 +104,29 @@ export interface components {
|
||||||
/** @example 2020-01-01T00:00:00Z */
|
/** @example 2020-01-01T00:00:00Z */
|
||||||
utc_ts: string;
|
utc_ts: string;
|
||||||
};
|
};
|
||||||
tp_messages: {
|
timePlanning: {
|
||||||
/** @example 1234567890123456800 */
|
enabled: boolean;
|
||||||
channelId: number;
|
channelId: components["schemas"]["idOrNull"];
|
||||||
|
rolesEnabled: boolean;
|
||||||
|
isAvailableRoleId: components["schemas"]["idOrNull"];
|
||||||
|
wantsToBeNotifieRoledId: components["schemas"]["idOrNull"];
|
||||||
messageIds: {
|
messageIds: {
|
||||||
/** @example 1234567890123456800 */
|
0: components["schemas"]["idOrNull"];
|
||||||
0: number | null;
|
1: components["schemas"]["idOrNull"];
|
||||||
/** @example 1234567890123456800 */
|
2: components["schemas"]["idOrNull"];
|
||||||
1: number | null;
|
3: components["schemas"]["idOrNull"];
|
||||||
/** @example 1234567890123456800 */
|
4: components["schemas"]["idOrNull"];
|
||||||
2: number | null;
|
5: components["schemas"]["idOrNull"];
|
||||||
/** @example 1234567890123456800 */
|
6: components["schemas"]["idOrNull"];
|
||||||
3: number | null;
|
|
||||||
/** @example 1234567890123456800 */
|
|
||||||
4: number | null;
|
|
||||||
/** @example 1234567890123456800 */
|
|
||||||
5: number | null;
|
|
||||||
/** @example 1234567890123456800 */
|
|
||||||
6: number | null;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
/** @example 1234567890123456789 */
|
||||||
|
id: string;
|
||||||
|
/** @example 1234567890123456789 */
|
||||||
|
idOrNull: string | null;
|
||||||
|
error: {
|
||||||
|
error?: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
responses: never;
|
responses: never;
|
||||||
parameters: never;
|
parameters: never;
|
||||||
|
@ -155,15 +155,21 @@ export interface operations {
|
||||||
};
|
};
|
||||||
/** @description Invalid ID supplied */
|
/** @description Invalid ID supplied */
|
||||||
400: {
|
400: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
/** @description Unauthorized */
|
/** @description Unauthorized */
|
||||||
401: {
|
401: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
/** @description Guild not found */
|
/** @description Guild not found */
|
||||||
404: {
|
404: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -187,16 +193,58 @@ export interface operations {
|
||||||
};
|
};
|
||||||
/** @description Invalid ID supplied */
|
/** @description Invalid ID supplied */
|
||||||
400: {
|
400: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
/** @description Unauthorized */
|
/** @description Unauthorized */
|
||||||
401: {
|
401: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
/** @description Guild not found */
|
/** @description Guild not found */
|
||||||
404: {
|
404: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Creates a guild's config by ID
|
||||||
|
* @description Create a guild's config when the bot is has joined a new guild.
|
||||||
|
*/
|
||||||
|
postGuildById: {
|
||||||
|
parameters: {
|
||||||
|
path: {
|
||||||
|
/** @description ID of guild's config to create */
|
||||||
|
guildId: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** @description successful operation */
|
||||||
|
204: {
|
||||||
content: never;
|
content: never;
|
||||||
};
|
};
|
||||||
|
/** @description Invalid ID supplied */
|
||||||
|
400: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Unauthorized */
|
||||||
|
401: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Guild not found */
|
||||||
|
404: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
|
@ -206,7 +254,7 @@ export interface operations {
|
||||||
deleteGuildById: {
|
deleteGuildById: {
|
||||||
parameters: {
|
parameters: {
|
||||||
path: {
|
path: {
|
||||||
/** @description ID of guild config to delete */
|
/** @description ID of guild's config to delete */
|
||||||
guildId: string;
|
guildId: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -217,26 +265,32 @@ export interface operations {
|
||||||
};
|
};
|
||||||
/** @description Invalid ID supplied */
|
/** @description Invalid ID supplied */
|
||||||
400: {
|
400: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
/** @description Unauthorized */
|
/** @description Unauthorized */
|
||||||
401: {
|
401: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
/** @description Guild not found */
|
/** @description Guild not found */
|
||||||
404: {
|
404: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Find the tp_messages of guild by ID
|
* Find the timePlanning of guild by ID
|
||||||
* @description Returns tp_messages for a guild
|
* @description Returns timePlanning for a guild
|
||||||
*/
|
*/
|
||||||
getTp_messagesOfGuildById: {
|
gettimePlanningOfGuildById: {
|
||||||
parameters: {
|
parameters: {
|
||||||
path: {
|
path: {
|
||||||
/** @description ID of guild's tp_messages to return */
|
/** @description ID of guild's timePlanning to return */
|
||||||
guildId: string;
|
guildId: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -244,42 +298,44 @@ export interface operations {
|
||||||
/** @description successful operation */
|
/** @description successful operation */
|
||||||
200: {
|
200: {
|
||||||
content: {
|
content: {
|
||||||
"application/json": components["schemas"]["tp_messages"];
|
"application/json": components["schemas"]["timePlanning"];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/** @description Time planning not enabled for this guild */
|
|
||||||
204: {
|
|
||||||
content: never;
|
|
||||||
};
|
|
||||||
/** @description Invalid ID supplied */
|
/** @description Invalid ID supplied */
|
||||||
400: {
|
400: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
/** @description Unauthorized */
|
/** @description Unauthorized */
|
||||||
401: {
|
401: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
/** @description Guild not found */
|
/** @description Guild not found */
|
||||||
404: {
|
404: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Put new message IDs for tp_messages of guild by ID
|
* Put new message IDs for timePlanning of guild by ID
|
||||||
* @description Returns tp_messages for a guild
|
* @description Returns timePlanning for a guild
|
||||||
*/
|
*/
|
||||||
putTp_messagesOfGuildById: {
|
puttimePlanningOfGuildById: {
|
||||||
parameters: {
|
parameters: {
|
||||||
path: {
|
path: {
|
||||||
/** @description ID of guild's tp_messages to return */
|
/** @description ID of guild's timePlanning to return */
|
||||||
guildId: string;
|
guildId: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/** @description Put new message IDs for tp_messages in channel */
|
/** @description Put new message IDs for timePlanning in channel */
|
||||||
requestBody: {
|
requestBody: {
|
||||||
content: {
|
content: {
|
||||||
"application/json": components["schemas"]["tp_messages"];
|
"application/json": components["schemas"]["timePlanning"];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
responses: {
|
responses: {
|
||||||
|
@ -289,30 +345,32 @@ export interface operations {
|
||||||
};
|
};
|
||||||
/** @description Invalid ID supplied */
|
/** @description Invalid ID supplied */
|
||||||
400: {
|
400: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
/** @description Unauthorized */
|
/** @description Unauthorized */
|
||||||
401: {
|
401: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
};
|
};
|
||||||
/** @description Time planning not enabled for this guild */
|
|
||||||
403: {
|
|
||||||
content: never;
|
|
||||||
};
|
};
|
||||||
/** @description Guild not found */
|
/** @description Guild not found */
|
||||||
404: {
|
404: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Find all matches of guild by ID
|
* Find all matches of guild by ID
|
||||||
* @description Returns tp_messages for a guild
|
* @description Returns timePlanning for a guild
|
||||||
*/
|
*/
|
||||||
getMatchesOfGuildById: {
|
getMatchesOfGuildById: {
|
||||||
parameters: {
|
parameters: {
|
||||||
path: {
|
path: {
|
||||||
/** @description ID of guild's tp_messages to return */
|
/** @description ID of guild's timePlanning to return */
|
||||||
guildId: string;
|
guildId: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -330,27 +388,29 @@ export interface operations {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/** @description Time planning not enabled for this guild */
|
|
||||||
204: {
|
|
||||||
content: never;
|
|
||||||
};
|
|
||||||
/** @description Invalid ID supplied */
|
/** @description Invalid ID supplied */
|
||||||
400: {
|
400: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
/** @description Unauthorized */
|
/** @description Unauthorized */
|
||||||
401: {
|
401: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
/** @description Guild not found */
|
/** @description Guild not found */
|
||||||
404: {
|
404: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Save a new created match of guild by ID
|
* Save a new created match of guild by ID
|
||||||
* @description Returns tp_messages for a guild
|
* @description Returns timePlanning for a guild
|
||||||
*/
|
*/
|
||||||
postMatchOfGuildById: {
|
postMatchOfGuildById: {
|
||||||
parameters: {
|
parameters: {
|
||||||
|
@ -380,15 +440,21 @@ export interface operations {
|
||||||
};
|
};
|
||||||
/** @description Invalid ID supplied */
|
/** @description Invalid ID supplied */
|
||||||
400: {
|
400: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
/** @description Unauthorized */
|
/** @description Unauthorized */
|
||||||
401: {
|
401: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
/** @description Guild not found */
|
/** @description Guild not found */
|
||||||
404: {
|
404: {
|
||||||
content: never;
|
content: {
|
||||||
|
"application/json": components["schemas"]["error"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
5
src/types/lucia-auth.d.ts
vendored
5
src/types/lucia-auth.d.ts
vendored
|
@ -3,7 +3,6 @@ import { lucia } from "~/lib/auth";
|
||||||
import { ExtractDataTypes, GetColumns } from "./db";
|
import { ExtractDataTypes, GetColumns } from "./db";
|
||||||
|
|
||||||
declare module "lucia" {
|
declare module "lucia" {
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
interface Register {
|
interface Register {
|
||||||
Lucia: typeof lucia;
|
Lucia: typeof lucia;
|
||||||
DatabaseUserAttributes: DatabaseUserAttributes;
|
DatabaseUserAttributes: DatabaseUserAttributes;
|
||||||
|
@ -11,6 +10,4 @@ declare module "lucia" {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DatabaseUserAttributes
|
interface DatabaseUserAttributes
|
||||||
extends ExtractDataTypes<GetColumns<typeof users>> {
|
extends ExtractDataTypes<GetColumns<typeof users>> {}
|
||||||
warst: string;
|
|
||||||
}
|
|
||||||
|
|
12
src/types/vinxi.d.ts
vendored
Normal file
12
src/types/vinxi.d.ts
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { H3EventContext as EventContext } from "h3/dist";
|
||||||
|
import { Session, User } from "lucia";
|
||||||
|
|
||||||
|
declare module "vinxi/http" {
|
||||||
|
interface H3EventContext extends EventContext {
|
||||||
|
user: User | null;
|
||||||
|
session: Session | null;
|
||||||
|
}
|
||||||
|
class H3Eventt {
|
||||||
|
context: H3EventContext;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue