Fix: Finished Backend
This commit is contained in:
parent
6b388729d9
commit
ffaf8d989e
30 changed files with 1478 additions and 873 deletions
|
@ -4,5 +4,8 @@
|
||||||
"node": true
|
"node": true
|
||||||
},
|
},
|
||||||
"plugins": ["solid"],
|
"plugins": ["solid"],
|
||||||
"extends": ["eslint:recommended", "plugin:solid/typescript"]
|
"extends": [
|
||||||
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
"plugin:solid/typescript"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
25
package.json
25
package.json
|
@ -23,31 +23,36 @@
|
||||||
"@lucia-auth/adapter-drizzle": "^1.0.2",
|
"@lucia-auth/adapter-drizzle": "^1.0.2",
|
||||||
"@paralleldrive/cuid2": "^2.2.2",
|
"@paralleldrive/cuid2": "^2.2.2",
|
||||||
"@solidjs/meta": "^0.29.3",
|
"@solidjs/meta": "^0.29.3",
|
||||||
"@solidjs/router": "^0.12.3",
|
"@solidjs/router": "^0.12.4",
|
||||||
"@solidjs/start": "^0.5.9",
|
"@solidjs/start": "^0.5.10",
|
||||||
"arctic": "^1.1.6",
|
"arctic": "^1.2.0",
|
||||||
"drizzle-orm": "^0.29.3",
|
"drizzle-orm": "^0.29.4",
|
||||||
|
"http-status": "^1.7.4",
|
||||||
|
"json-stable-stringify": "^1.1.1",
|
||||||
"lucia": "^3.0.1",
|
"lucia": "^3.0.1",
|
||||||
"moment-timezone": "^0.5.45",
|
"moment-timezone": "^0.5.45",
|
||||||
"openapi-fetch": "^0.9.1",
|
"object-hash": "^3.0.0",
|
||||||
|
"openapi-fetch": "^0.9.2",
|
||||||
"postgres": "^3.4.3",
|
"postgres": "^3.4.3",
|
||||||
"solid-js": "^1.8.15",
|
"solid-js": "^1.8.15",
|
||||||
"vinxi": "^0.3.3"
|
"vinxi": "^0.3.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "^7.0.1",
|
"@types/json-stable-stringify": "^1.0.36",
|
||||||
"dotenv": "^16.4.4",
|
"@types/object-hash": "^3.0.6",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^7.0.2",
|
||||||
|
"dotenv": "^16.4.5",
|
||||||
"drizzle-kit": "^0.20.14",
|
"drizzle-kit": "^0.20.14",
|
||||||
"drizzle-zod": "^0.5.1",
|
"drizzle-zod": "^0.5.1",
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-solid": "^0.13.1",
|
"eslint-plugin-solid": "^0.13.1",
|
||||||
"h3": "^1.10.1",
|
"h3": "^1.10.2",
|
||||||
"openapi-typescript": "^6.7.4",
|
"openapi-typescript": "^6.7.4",
|
||||||
"pg": "^8.11.3",
|
"pg": "^8.11.3",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"prettier-plugin-organize-imports": "^3.2.4",
|
"prettier-plugin-organize-imports": "^3.2.4",
|
||||||
"sass": "^1.71.0",
|
"sass": "^1.71.1",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
"zod": "3.22.4"
|
"zod": "3.22.4"
|
||||||
},
|
},
|
||||||
|
|
660
pnpm-lock.yaml
660
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -10,19 +10,22 @@
|
||||||
"version": "0.0.0"
|
"version": "0.0.0"
|
||||||
},
|
},
|
||||||
"paths": {
|
"paths": {
|
||||||
"/api/boot/config": {
|
"/api/boot": {
|
||||||
"get": {
|
"get": {
|
||||||
"tags": ["Guild configs"],
|
"tags": ["Bot bootup"],
|
||||||
"summary": "Find a guild's config by ID",
|
"summary": "Retrieve all guild's configs",
|
||||||
"description": "Returns a single guild's config.",
|
"description": "Returns all guild's configs.",
|
||||||
"operationId": "getGuildsFromBoot",
|
"operationId": "getGuildsForBoot",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "successful operation",
|
"description": "successful operation",
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/schemas/bootConfig"
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/guildConfig"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,20 +33,23 @@
|
||||||
"400": {
|
"400": {
|
||||||
"description": "Invalid ID supplied"
|
"description": "Invalid ID supplied"
|
||||||
},
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized"
|
||||||
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"description": "Guild not found"
|
"description": "Guild not found"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"bot_token": []
|
"basicAuth": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/{guildId}/config": {
|
"/api/{guildId}/config": {
|
||||||
"get": {
|
"get": {
|
||||||
"tags": ["Guild configs"],
|
"tags": ["Guild config"],
|
||||||
"summary": "Find a guild's config by ID",
|
"summary": "Find a guild's config by ID",
|
||||||
"description": "Returns a single guild's config.",
|
"description": "Returns a single guild's config.",
|
||||||
"operationId": "getGuildById",
|
"operationId": "getGuildById",
|
||||||
|
@ -73,18 +79,21 @@
|
||||||
"400": {
|
"400": {
|
||||||
"description": "Invalid ID supplied"
|
"description": "Invalid ID supplied"
|
||||||
},
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized"
|
||||||
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"description": "Guild not found"
|
"description": "Guild not found"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"bot_token": []
|
"basicAuth": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
"tags": ["Guild configs"],
|
"tags": ["Guild config"],
|
||||||
"summary": "Deletes a guild's config by ID",
|
"summary": "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.",
|
||||||
"operationId": "deleteGuildById",
|
"operationId": "deleteGuildById",
|
||||||
|
@ -107,13 +116,16 @@
|
||||||
"400": {
|
"400": {
|
||||||
"description": "Invalid ID supplied"
|
"description": "Invalid ID supplied"
|
||||||
},
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized"
|
||||||
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"description": "Guild not found"
|
"description": "Guild not found"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"bot_token": []
|
"basicAuth": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -153,19 +165,22 @@
|
||||||
"400": {
|
"400": {
|
||||||
"description": "Invalid ID supplied"
|
"description": "Invalid ID supplied"
|
||||||
},
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized"
|
||||||
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"description": "Guild not found"
|
"description": "Guild not found"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"bot_token": []
|
"basicAuth": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"put": {
|
"put": {
|
||||||
"tags": ["Time planning messages"],
|
"tags": ["Time planning messages"],
|
||||||
"summary": "Put message IDs for tp_messages of guild by ID",
|
"summary": "Put new message IDs for tp_messages of guild by ID",
|
||||||
"description": "Returns tp_messages for a guild",
|
"description": "Returns tp_messages for a guild",
|
||||||
"operationId": "putTp_messagesOfGuildById",
|
"operationId": "putTp_messagesOfGuildById",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
|
@ -180,30 +195,37 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"requestBody": {
|
||||||
"200": {
|
"description": "Put new message IDs for tp_messages in channel",
|
||||||
"description": "successful operation",
|
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/schemas/tp_messages"
|
"$ref": "#/components/schemas/tp_messages"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
"204": {
|
"204": {
|
||||||
"description": "Time planning not enabled for this guild"
|
"description": "successful operation"
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
"description": "Invalid ID supplied"
|
"description": "Invalid ID supplied"
|
||||||
},
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized"
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "Time planning not enabled for this guild"
|
||||||
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"description": "Guild not found"
|
"description": "Guild not found"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"bot_token": []
|
"basicAuth": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -232,9 +254,20 @@
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["matches", "timezone"],
|
||||||
|
"properties": {
|
||||||
|
"matches": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/components/schemas/tp_messages"
|
"$ref": "#/components/schemas/match"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"timezone": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "text",
|
||||||
|
"example": "Europe/Berlin"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,21 +279,22 @@
|
||||||
"400": {
|
"400": {
|
||||||
"description": "Invalid ID supplied"
|
"description": "Invalid ID supplied"
|
||||||
},
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized"
|
||||||
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"description": "Guild not found"
|
"description": "Guild not found"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"bot_token": []
|
"basicAuth": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"/api/{guildId}/matches/{channelId}": {
|
|
||||||
"post": {
|
"post": {
|
||||||
"tags": ["Matches"],
|
"tags": ["Matches"],
|
||||||
"summary": "Save a new created match in channel of guild by IDs",
|
"summary": "Save a new created match of guild by ID",
|
||||||
"description": "Returns tp_messages for a guild",
|
"description": "Returns tp_messages for a guild",
|
||||||
"operationId": "postMatchOfGuildById",
|
"operationId": "postMatchOfGuildById",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
|
@ -273,108 +307,48 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "varchar(20)"
|
"format": "varchar(20)"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "channelId",
|
|
||||||
"in": "path",
|
|
||||||
"description": "ID of match's channel to set",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "varchar(20)"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"requestBody": {
|
||||||
"200": {
|
"description": "Save a new created match in channel",
|
||||||
"description": "successful operation",
|
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/schemas/tp_messages"
|
"type": "object",
|
||||||
|
"required": ["match", "timezone"],
|
||||||
|
"properties": {
|
||||||
|
"match": {
|
||||||
|
"$ref": "#/components/schemas/match"
|
||||||
|
},
|
||||||
|
"timezone": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "text",
|
||||||
|
"example": "Europe/Berlin",
|
||||||
|
"description": "Has to match guild tz"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
"204": {
|
"204": {
|
||||||
"description": "Time planning not enabled for this guild"
|
"description": "successful operation"
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
"description": "Invalid ID supplied"
|
"description": "Invalid ID supplied"
|
||||||
},
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized"
|
||||||
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"description": "Guild not found"
|
"description": "Guild not found"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"bot_token": []
|
"basicAuth": []
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/{guildId}/matches/{channelId}/{matchMessageId}": {
|
|
||||||
"put": {
|
|
||||||
"tags": ["Matches"],
|
|
||||||
"summary": "Set state for match of guild by IDs",
|
|
||||||
"description": "Returns tp_messages for a guild",
|
|
||||||
"operationId": "putMatchOfGuildById",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "guildId",
|
|
||||||
"in": "path",
|
|
||||||
"description": "ID of guild's tp_messages to return",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "varchar(20)"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "channelId",
|
|
||||||
"in": "path",
|
|
||||||
"description": "ID of match's channel to set",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "varchar(20)"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "matchMessageId",
|
|
||||||
"in": "path",
|
|
||||||
"description": "ID of match's message Id to set",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "varchar(20)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "successful operation",
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/components/schemas/tp_messages"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"204": {
|
|
||||||
"description": "Time planning not enabled for this guild"
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Invalid ID supplied"
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "Guild not found"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"bot_token": []
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -382,21 +356,11 @@
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
"schemas": {
|
"schemas": {
|
||||||
"bootConfig": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"guilds": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/components/schemas/guildConfig"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"guildConfig": {
|
"guildConfig": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"required": ["guildId", "timezone", "features", "matches", "checksum"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"guildID": {
|
"guildId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "varchar(20)",
|
"format": "varchar(20)",
|
||||||
"example": "1234567890123456789"
|
"example": "1234567890123456789"
|
||||||
|
@ -408,14 +372,27 @@
|
||||||
},
|
},
|
||||||
"features": {
|
"features": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"required": ["timePlanning"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"time_planning": {
|
"timePlanning": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enabled",
|
||||||
|
"channelId",
|
||||||
|
"targetMinute",
|
||||||
|
"targetHour",
|
||||||
|
"targetDay",
|
||||||
|
"roles"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"channelID": {
|
"enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"channelId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "varchar(20)",
|
"format": "varchar(20)",
|
||||||
"example": "1234567890123456789"
|
"example": "1234567890123456789",
|
||||||
|
"nullable": true
|
||||||
},
|
},
|
||||||
"targetMinute": {
|
"targetMinute": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
|
@ -431,6 +408,11 @@
|
||||||
},
|
},
|
||||||
"roles": {
|
"roles": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enabled",
|
||||||
|
"isAvailableRoleId",
|
||||||
|
"wantsToBeNotifieRoledId"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"enabled": {
|
"enabled": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
@ -458,13 +440,25 @@
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/components/schemas/match"
|
"$ref": "#/components/schemas/match"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"checksum": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"match": {
|
"match": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"channelId",
|
||||||
|
"matchType",
|
||||||
|
"createrId",
|
||||||
|
"roleId",
|
||||||
|
"opponentName",
|
||||||
|
"messageId",
|
||||||
|
"utc_ts"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"channelID": {
|
"channelId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "varcharq(20)",
|
"format": "varcharq(20)",
|
||||||
"example": "1234567890123456789"
|
"example": "1234567890123456789"
|
||||||
|
@ -489,54 +483,81 @@
|
||||||
"format": "varchar(100)",
|
"format": "varchar(100)",
|
||||||
"example": "?"
|
"example": "?"
|
||||||
},
|
},
|
||||||
"messsageId": {
|
"messageId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "varchar(20)",
|
"format": "varchar(20)",
|
||||||
"example": "1234567890123456789"
|
"example": "1234567890123456789"
|
||||||
},
|
},
|
||||||
"utc_ts": {
|
"utc_ts": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"example": "1706180188"
|
"example": "2020-01-01T00:00:00Z"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tp_messages": {
|
"tp_messages": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"required": ["channelId", "messageIds"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"guildId": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "varchar(20)",
|
|
||||||
"example": "1234567890123456789"
|
|
||||||
},
|
|
||||||
"channelId": {
|
"channelId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "varchar(20)",
|
"format": "varchar(20)",
|
||||||
"example": "1234567890123456789"
|
"example": "1234567890123456789"
|
||||||
},
|
},
|
||||||
"messageIds": {
|
"messageIds": {
|
||||||
"type": "array",
|
"type": "object",
|
||||||
"items": {
|
"required": ["0", "1", "2", "3", "4", "5", "6"],
|
||||||
|
"properties": {
|
||||||
|
"0": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "varchar(20)"
|
"format": "varchar(20)",
|
||||||
|
"example": "1234567890123456789",
|
||||||
|
"nullable": true
|
||||||
},
|
},
|
||||||
"example": [
|
"1": {
|
||||||
"1234567890123456789",
|
"type": "string",
|
||||||
"1234567890123456789",
|
"format": "varchar(20)",
|
||||||
"1234567890123456789",
|
"example": "1234567890123456789",
|
||||||
"1234567890123456789",
|
"nullable": true
|
||||||
"1234567890123456789",
|
},
|
||||||
"1234567890123456789",
|
"2": {
|
||||||
"1234567890123456789"
|
"type": "string",
|
||||||
]
|
"format": "varchar(20)",
|
||||||
|
"example": "1234567890123456789",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "varchar(20)",
|
||||||
|
"example": "1234567890123456789",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "varchar(20)",
|
||||||
|
"example": "1234567890123456789",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "varchar(20)",
|
||||||
|
"example": "1234567890123456789",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "varchar(20)",
|
||||||
|
"example": "1234567890123456789",
|
||||||
|
"nullable": true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"securitySchemes": {
|
"securitySchemes": {
|
||||||
"bot_token": {
|
"basicAuth": {
|
||||||
"type": "http",
|
"type": "http",
|
||||||
"scheme": "bearer",
|
"scheme": "basic"
|
||||||
"bearerFormat": "JWT"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"guilds": [
|
|
||||||
{
|
|
||||||
"guildID": "some ID",
|
|
||||||
"UTCOffset": 0,
|
|
||||||
"features": {
|
|
||||||
"time_planning": {
|
|
||||||
"channelID": "some ID",
|
|
||||||
"targetWeekday": 0,
|
|
||||||
"targetHour": 0,
|
|
||||||
"targetMinute": 0,
|
|
||||||
"isAvailableRoleId": "some ID",
|
|
||||||
"wantsToBeNotifieRoledId": "some ID"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"matches": [
|
|
||||||
{
|
|
||||||
"channelID": "some ID",
|
|
||||||
"matchType": "",
|
|
||||||
"createrId": "some ID",
|
|
||||||
"roleId": "some ID",
|
|
||||||
"opponentName": "",
|
|
||||||
"messsageId": "",
|
|
||||||
"plannedFor": 1704314625000
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"accessToken": "some Token"
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { faCirclePlus } from "@fortawesome/pro-regular-svg-icons";
|
import { faCirclePlus } from "@fortawesome/pro-regular-svg-icons";
|
||||||
import { JSX, Show, Suspense } from "solid-js";
|
import { JSX, Show } from "solid-js";
|
||||||
import "../styles/components/NavBar.scss";
|
import "../styles/components/NavBar.scss";
|
||||||
import { FontAwesomeIcon } from "./FontAwesomeIcon";
|
import { FontAwesomeIcon } from "./FontAwesomeIcon";
|
||||||
import NavUser from "./NavUser";
|
import NavUser from "./NavUser";
|
||||||
|
@ -41,9 +41,7 @@ function NavBar() {
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon class="lower" icon={faCirclePlus} size="xl" />
|
<FontAwesomeIcon class="lower" icon={faCirclePlus} size="xl" />
|
||||||
</Li>
|
</Li>
|
||||||
<Suspense>
|
|
||||||
<NavUser />
|
<NavUser />
|
||||||
</Suspense>
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,48 +3,27 @@ import {
|
||||||
faArrowRightToBracket,
|
faArrowRightToBracket,
|
||||||
faGear,
|
faGear,
|
||||||
} from "@fortawesome/pro-regular-svg-icons";
|
} from "@fortawesome/pro-regular-svg-icons";
|
||||||
import { User } from "lucia";
|
import { cache, createAsync } from "@solidjs/router";
|
||||||
import { Show, createResource } from "solid-js";
|
import { Show } from "solid-js";
|
||||||
import { getRequestEvent } from "solid-js/web";
|
import { getRequestEvent } from "solid-js/web";
|
||||||
import { FontAwesomeIcon } from "./FontAwesomeIcon";
|
import { FontAwesomeIcon } from "./FontAwesomeIcon";
|
||||||
import { Li } from "./NavBar";
|
import { Li } from "./NavBar";
|
||||||
|
|
||||||
async function getUser(): Promise<
|
async function getUser() {
|
||||||
| ({
|
|
||||||
success: false;
|
|
||||||
message: string;
|
|
||||||
// user?: undefined;
|
|
||||||
} & Partial<User>)
|
|
||||||
| ({
|
|
||||||
success: true;
|
|
||||||
message?: undefined;
|
|
||||||
} & User)
|
|
||||||
> {
|
|
||||||
"use server";
|
"use server";
|
||||||
|
|
||||||
const event = getRequestEvent();
|
const event = getRequestEvent();
|
||||||
if (!event) return { success: false, message: "No request event!" };
|
|
||||||
|
|
||||||
const pathname = new URL(event.request.url).pathname;
|
return event?.nativeEvent.context.user;
|
||||||
const { user } = event.nativeEvent.context;
|
|
||||||
if (!user) return { success: false, message: "User not logged in!" };
|
|
||||||
|
|
||||||
console.log("userInfo", pathname, "success");
|
|
||||||
|
|
||||||
return { success: true, ...user };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cachedUser = cache(() => getUser(), "userInfo");
|
||||||
|
|
||||||
function NavUser() {
|
function NavUser() {
|
||||||
const [user] = createResource(async () => {
|
const user = createAsync(() => cachedUser());
|
||||||
const user = await getUser();
|
|
||||||
|
|
||||||
if (!user.success) console.error("userInfo", user.message);
|
|
||||||
|
|
||||||
return user;
|
|
||||||
});
|
|
||||||
const pfp = () => {
|
const pfp = () => {
|
||||||
const thisUser = user();
|
const thisUser = user();
|
||||||
if (!thisUser?.success) return "";
|
if (!thisUser?.id) return "";
|
||||||
|
|
||||||
return thisUser.image
|
return thisUser.image
|
||||||
? `https://cdn.discordapp.com/avatars/${thisUser.discord_id}/${thisUser.image}.png`
|
? `https://cdn.discordapp.com/avatars/${thisUser.discord_id}/${thisUser.image}.png`
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { relations } from "drizzle-orm";
|
import { relations } from "drizzle-orm";
|
||||||
import {
|
import {
|
||||||
boolean,
|
boolean,
|
||||||
integer,
|
|
||||||
pgTable,
|
pgTable,
|
||||||
|
primaryKey,
|
||||||
serial,
|
serial,
|
||||||
smallint,
|
smallint,
|
||||||
text,
|
text,
|
||||||
|
@ -37,10 +37,51 @@ export const discordTokens = pgTable("tokens", {
|
||||||
expiresAt: timestamp("expires_at", { mode: "date" }).notNull(),
|
expiresAt: timestamp("expires_at", { mode: "date" }).notNull(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const matchPlannings = pgTable("match_planning", {
|
export const guilds = pgTable("guilds", {
|
||||||
|
id: varchar("id", { length: 20 }).primaryKey(),
|
||||||
|
timezone: text("timezone").notNull().default("Etc/UTC"),
|
||||||
|
tpEnabled: boolean("tp_enabled").notNull().default(false),
|
||||||
|
tpChannelId: varchar("tp_channel_id", { length: 20 }),
|
||||||
|
tpInterval: smallint("target_interval").notNull(),
|
||||||
|
tpRoles: boolean("tp_roles").notNull(),
|
||||||
|
isAvailableRoleId: varchar("is_available_role_id", { length: 20 }),
|
||||||
|
wantsToBeNotifieRoledId: varchar("wants_to_be_notified_role_id", {
|
||||||
|
length: 20,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const guildsRelations = relations(guilds, ({ many }) => ({
|
||||||
|
tpMessages: many(tpMessages),
|
||||||
|
matches: many(matches),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const tpMessages = pgTable(
|
||||||
|
"tp_messages",
|
||||||
|
{
|
||||||
|
messageId: varchar("message_id", { length: 20 }),
|
||||||
|
day: smallint("day").notNull(),
|
||||||
|
guildId: varchar("guild_id", { length: 20 })
|
||||||
|
.notNull()
|
||||||
|
.references(() => guilds.id, { onDelete: "cascade" }),
|
||||||
|
},
|
||||||
|
(table) => {
|
||||||
|
return {
|
||||||
|
pk: primaryKey({ columns: [table.guildId, table.day] }),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const tpMessagesRelations = relations(tpMessages, ({ one }) => ({
|
||||||
|
guild: one(guilds, {
|
||||||
|
fields: [tpMessages.guildId],
|
||||||
|
references: [guilds.id],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const matches = pgTable("matches", {
|
||||||
id: serial("id").primaryKey(),
|
id: serial("id").primaryKey(),
|
||||||
channelId: varchar("channel_id", { length: 20 }).notNull(),
|
channelId: varchar("channel_id", { length: 20 }).notNull(),
|
||||||
matchtype: varchar("match_type", { length: 50 }).notNull(),
|
matchType: varchar("match_type", { length: 50 }).notNull(),
|
||||||
createrId: varchar("creater_id", { length: 20 }).notNull(),
|
createrId: varchar("creater_id", { length: 20 }).notNull(),
|
||||||
roleId: varchar("role_id", { length: 20 }).notNull(),
|
roleId: varchar("role_id", { length: 20 }).notNull(),
|
||||||
opponentName: varchar("opponent_name", { length: 100 }).notNull(),
|
opponentName: varchar("opponent_name", { length: 100 }).notNull(),
|
||||||
|
@ -51,65 +92,9 @@ export const matchPlannings = pgTable("match_planning", {
|
||||||
.references(() => guilds.id, { onDelete: "cascade" }),
|
.references(() => guilds.id, { onDelete: "cascade" }),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const matchPlanningsRelations = relations(matchPlannings, ({ one }) => ({
|
export const matchPlanningsRelations = relations(matches, ({ one }) => ({
|
||||||
guild: one(guilds, {
|
guild: one(guilds, {
|
||||||
fields: [matchPlannings.guildId],
|
fields: [matches.guildId],
|
||||||
references: [guilds.id],
|
references: [guilds.id],
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const guilds = pgTable("guild", {
|
|
||||||
id: varchar("id", { length: 20 }).primaryKey(),
|
|
||||||
timezone: text("timezone").notNull(),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const guildsRelations = relations(guilds, ({ one, many }) => ({
|
|
||||||
matches: many(matchPlannings),
|
|
||||||
timePlanning: one(timePlannings, {
|
|
||||||
fields: [guilds.id],
|
|
||||||
references: [timePlannings.guildId],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const timePlannings = pgTable("time_planning", {
|
|
||||||
id: serial("id").primaryKey(),
|
|
||||||
guildId: varchar("guild_id", { length: 20 })
|
|
||||||
.notNull()
|
|
||||||
.unique()
|
|
||||||
.references(() => guilds.id, {
|
|
||||||
onDelete: "cascade",
|
|
||||||
}),
|
|
||||||
channelId: varchar("channel_id", { length: 20 }).notNull(),
|
|
||||||
target_interval: smallint("target_interval").notNull(),
|
|
||||||
roles: boolean("roles").notNull(),
|
|
||||||
isAvailableRoleId: varchar("is_available_role_id", { length: 20 }),
|
|
||||||
wantsToBeNotifieRoledId: varchar("wants_to_be_notified_role_id", {
|
|
||||||
length: 20,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const timePlanningsRelations = relations(
|
|
||||||
timePlannings,
|
|
||||||
({ one, many }) => ({
|
|
||||||
guild: one(guilds, {
|
|
||||||
fields: [timePlannings.guildId],
|
|
||||||
references: [guilds.id],
|
|
||||||
}),
|
|
||||||
messages: many(tpMessages),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
export const tpMessages = pgTable("tp_message", {
|
|
||||||
messageId: varchar("message_id", { length: 20 }).primaryKey(),
|
|
||||||
day: smallint("day").notNull(),
|
|
||||||
planId: integer("plan_id")
|
|
||||||
.notNull()
|
|
||||||
.references(() => timePlannings.id, { onDelete: "cascade" }),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const tpMessagesRelations = relations(tpMessages, ({ one }) => ({
|
|
||||||
plan: one(timePlannings, {
|
|
||||||
fields: [tpMessages.planId],
|
|
||||||
references: [timePlannings.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { DrizzlePostgreSQLAdapter } from "@lucia-auth/adapter-drizzle";
|
import { DrizzlePostgreSQLAdapter } from "@lucia-auth/adapter-drizzle";
|
||||||
import { Discord } from "arctic";
|
import { Discord } from "arctic";
|
||||||
import { PgColumn, PgTableWithColumns } from "drizzle-orm/pg-core";
|
|
||||||
import { Lucia } from "lucia";
|
import { Lucia } from "lucia";
|
||||||
import db from "~/drizzle";
|
import db from "~/drizzle";
|
||||||
import { sessions, users } from "~/drizzle/schema";
|
import { sessions, users } from "~/drizzle/schema";
|
||||||
|
@ -17,30 +16,16 @@ export const lucia = new Lucia(adapter, {
|
||||||
getUserAttributes: (attributes) => attributes,
|
getUserAttributes: (attributes) => attributes,
|
||||||
});
|
});
|
||||||
|
|
||||||
declare module "lucia" {
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
interface Register {
|
|
||||||
Lucia: typeof lucia;
|
|
||||||
DatabaseUserAttributes: DatabaseUserAttributes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetColumns<T> =
|
|
||||||
T extends PgTableWithColumns<infer First> ? First["columns"] : never;
|
|
||||||
|
|
||||||
type ExtractDataTypes<T> = {
|
|
||||||
[K in keyof T]: T[K] extends PgColumn<infer DataType, any, any>
|
|
||||||
? DataType["data"]
|
|
||||||
: never;
|
|
||||||
};
|
|
||||||
|
|
||||||
interface DatabaseUserAttributes
|
|
||||||
extends ExtractDataTypes<GetColumns<typeof users>> {
|
|
||||||
warst: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const discord = new Discord(
|
export const discord = new Discord(
|
||||||
import.meta.env.VITE_DISCORD_CLIENT_ID,
|
import.meta.env.VITE_DISCORD_CLIENT_ID,
|
||||||
import.meta.env.VITE_DISCORD_CLIENT_SECRET,
|
import.meta.env.VITE_DISCORD_CLIENT_SECRET,
|
||||||
import.meta.env.VITE_AUTH_REDIRECT_URL,
|
import.meta.env.VITE_AUTH_REDIRECT_URL,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const unencoded = `${import.meta.env.VITE_DISCORD_CLIENT_ID}:${import.meta.env.VITE_DISCORD_CLIENT_SECRET}`;
|
||||||
|
const encoded = btoa(unencoded);
|
||||||
|
|
||||||
|
export const BasicAuth = {
|
||||||
|
unencoded: `Basic ${unencoded}`,
|
||||||
|
encoded: `Basic ${encoded}`,
|
||||||
|
};
|
||||||
|
|
83
src/lib/responseBuilders.ts
Normal file
83
src/lib/responseBuilders.ts
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
import stringify from "json-stable-stringify";
|
||||||
|
import objectHash from "object-hash";
|
||||||
|
|
||||||
|
export const buildMatches = (
|
||||||
|
matches: {
|
||||||
|
id: number;
|
||||||
|
messageId: string;
|
||||||
|
guildId: string;
|
||||||
|
channelId: string;
|
||||||
|
matchType: string;
|
||||||
|
createrId: string;
|
||||||
|
roleId: string;
|
||||||
|
opponentName: string;
|
||||||
|
utc_ts: Date;
|
||||||
|
}[],
|
||||||
|
) =>
|
||||||
|
matches.map(
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
({ id, guildId, utc_ts, ...match }) => ({
|
||||||
|
...match,
|
||||||
|
utc_ts: utc_ts.toISOString(),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
export function buildConfig(guildQuery: {
|
||||||
|
id: string;
|
||||||
|
timezone: string;
|
||||||
|
tpEnabled: boolean;
|
||||||
|
tpChannelId: string | null;
|
||||||
|
tpInterval: number;
|
||||||
|
tpRoles: boolean;
|
||||||
|
isAvailableRoleId: string | null;
|
||||||
|
wantsToBeNotifieRoledId: string | null;
|
||||||
|
tpMessages: {
|
||||||
|
messageId: string | null;
|
||||||
|
day: number;
|
||||||
|
guildId: string;
|
||||||
|
}[];
|
||||||
|
matches: {
|
||||||
|
id: number;
|
||||||
|
messageId: string;
|
||||||
|
guildId: string;
|
||||||
|
channelId: string;
|
||||||
|
matchType: string;
|
||||||
|
createrId: string;
|
||||||
|
roleId: string;
|
||||||
|
opponentName: string;
|
||||||
|
utc_ts: Date;
|
||||||
|
}[];
|
||||||
|
}) {
|
||||||
|
const {
|
||||||
|
id,
|
||||||
|
timezone,
|
||||||
|
tpEnabled,
|
||||||
|
tpChannelId,
|
||||||
|
tpInterval,
|
||||||
|
tpRoles,
|
||||||
|
isAvailableRoleId,
|
||||||
|
wantsToBeNotifieRoledId,
|
||||||
|
} = guildQuery;
|
||||||
|
|
||||||
|
const targetMinute = tpInterval & 63;
|
||||||
|
const targetHour = (tpInterval >> 6) & 31;
|
||||||
|
const targetDay = (tpInterval >> 11) & 7;
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
guildId: id,
|
||||||
|
timezone,
|
||||||
|
features: {
|
||||||
|
timePlanning: {
|
||||||
|
enabled: tpEnabled,
|
||||||
|
channelId: tpChannelId,
|
||||||
|
targetMinute,
|
||||||
|
targetHour,
|
||||||
|
targetDay,
|
||||||
|
roles: { enabled: tpRoles, isAvailableRoleId, wantsToBeNotifieRoledId },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
matches: buildMatches(guildQuery.matches),
|
||||||
|
checksum: objectHash(stringify(guildQuery)),
|
||||||
|
};
|
||||||
|
return payload;
|
||||||
|
}
|
39
src/lib/responses.ts
Normal file
39
src/lib/responses.ts
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import httpStatus from "http-status";
|
||||||
|
import {
|
||||||
|
APIResponse,
|
||||||
|
Methods,
|
||||||
|
MyPaths,
|
||||||
|
ResponseSchemas,
|
||||||
|
StatusCodes,
|
||||||
|
} from "~/types/backend";
|
||||||
|
|
||||||
|
export function ErrorResponse<
|
||||||
|
P extends MyPaths,
|
||||||
|
M extends Methods<P>,
|
||||||
|
C extends StatusCodes<P, M> = StatusCodes<P, M>,
|
||||||
|
>(code: C, error?: string): APIResponse<P, M> {
|
||||||
|
const responseData = {
|
||||||
|
error: error ?? httpStatus[`${httpStatus[code]}_NAME`],
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(responseData);
|
||||||
|
return new Response(JSON.stringify(responseData), {
|
||||||
|
status: httpStatus[code],
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Res<
|
||||||
|
P extends MyPaths,
|
||||||
|
M extends Methods<P>,
|
||||||
|
C extends StatusCodes<P, M> = StatusCodes<P, M>,
|
||||||
|
>(code: C, payload: ResponseSchemas<P, M, C>): APIResponse<P, M> {
|
||||||
|
return new Response(payload === null ? null : JSON.stringify(payload), {
|
||||||
|
status: httpStatus[code],
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
37
src/lib/zod.ts
Normal file
37
src/lib/zod.ts
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import moment from "moment-timezone";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const zodId = z
|
||||||
|
.string()
|
||||||
|
.refine((value) => /^\d{7,20}$/.test(value), "Invalid ID supplied");
|
||||||
|
|
||||||
|
export const zodTpMessages = z.object({
|
||||||
|
channelId: zodId,
|
||||||
|
messageIds: z.object({
|
||||||
|
"0": zodId.nullable(),
|
||||||
|
"1": zodId.nullable(),
|
||||||
|
"2": zodId.nullable(),
|
||||||
|
"3": zodId.nullable(),
|
||||||
|
"4": zodId.nullable(),
|
||||||
|
"5": zodId.nullable(),
|
||||||
|
"6": zodId.nullable(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const zodMatch = z.object({
|
||||||
|
match: z.object({
|
||||||
|
channelId: zodId,
|
||||||
|
createrId: zodId,
|
||||||
|
messageId: zodId,
|
||||||
|
roleId: zodId,
|
||||||
|
matchType: z.string(),
|
||||||
|
opponentName: z.string(),
|
||||||
|
utc_ts: z.string().datetime(),
|
||||||
|
}),
|
||||||
|
timezone: z
|
||||||
|
.string()
|
||||||
|
.refine(
|
||||||
|
(value) => moment.tz.names().includes(value),
|
||||||
|
"Unknown timezone supplied",
|
||||||
|
),
|
||||||
|
});
|
73
src/routes/api/[guildId]/config.ts
Normal file
73
src/routes/api/[guildId]/config.ts
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
import { APIEvent } from "@solidjs/start/server/types";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import db from "~/drizzle";
|
||||||
|
import { guilds } from "~/drizzle/schema";
|
||||||
|
import { BasicAuth } from "~/lib/auth";
|
||||||
|
import { buildConfig } from "~/lib/responseBuilders";
|
||||||
|
import { ErrorResponse, Res } from "~/lib/responses";
|
||||||
|
import { zodId } from "~/lib/zod";
|
||||||
|
import { APIResponse } from "~/types/backend";
|
||||||
|
|
||||||
|
type Path = "/api/{guildId}/config";
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
event: APIEvent,
|
||||||
|
): Promise<APIResponse<Path, "get">> => {
|
||||||
|
switch (event.request.headers.get("authorization")) {
|
||||||
|
case BasicAuth.unencoded:
|
||||||
|
case BasicAuth.encoded:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ErrorResponse("UNAUTHORIZED");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
zodId.parse(event.params.guildId);
|
||||||
|
} catch (e) {
|
||||||
|
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
const guildQuery = await db.query.guilds
|
||||||
|
.findFirst({
|
||||||
|
where: eq(guilds.id, event.params.guildId),
|
||||||
|
with: { tpMessages: true, matches: true },
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
if (!guildQuery) return ErrorResponse("NOT_FOUND");
|
||||||
|
|
||||||
|
return Res("OK", buildConfig(guildQuery));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DELETE = async (
|
||||||
|
event: APIEvent,
|
||||||
|
): Promise<APIResponse<Path, "delete">> => {
|
||||||
|
switch (event.request.headers.get("authorization")) {
|
||||||
|
case BasicAuth.unencoded:
|
||||||
|
case BasicAuth.encoded:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ErrorResponse("UNAUTHORIZED");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
zodId.parse(event.params.guildId);
|
||||||
|
} catch (e) {
|
||||||
|
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
const guildQuery = await db.query.guilds
|
||||||
|
.findFirst({
|
||||||
|
where: eq(guilds.id, event.params.guildId),
|
||||||
|
with: { tpMessages: true, matches: true },
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
if (!guildQuery) return ErrorResponse("NOT_FOUND");
|
||||||
|
|
||||||
|
await db.delete(guilds).where(eq(guilds.id, event.params.guildId)).execute();
|
||||||
|
|
||||||
|
return Res("NO_CONTENT", null);
|
||||||
|
};
|
93
src/routes/api/[guildId]/matches.ts
Normal file
93
src/routes/api/[guildId]/matches.ts
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
import { APIEvent } from "@solidjs/start/server/types";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import db from "~/drizzle";
|
||||||
|
import { guilds, matches } from "~/drizzle/schema";
|
||||||
|
import { BasicAuth } from "~/lib/auth";
|
||||||
|
import { buildMatches } from "~/lib/responseBuilders";
|
||||||
|
import { ErrorResponse, Res } from "~/lib/responses";
|
||||||
|
import { zodMatch } from "~/lib/zod";
|
||||||
|
import { APIResponse, RequestBody } from "~/types/backend";
|
||||||
|
|
||||||
|
type Path = "/api/{guildId}/matches";
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
event: APIEvent,
|
||||||
|
): Promise<APIResponse<Path, "get">> => {
|
||||||
|
switch (event.request.headers.get("authorization")) {
|
||||||
|
case BasicAuth.unencoded:
|
||||||
|
case BasicAuth.encoded:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ErrorResponse("UNAUTHORIZED");
|
||||||
|
}
|
||||||
|
|
||||||
|
const guild = await db.query.guilds
|
||||||
|
.findFirst({
|
||||||
|
where: eq(guilds.id, event.params.guildId),
|
||||||
|
with: {
|
||||||
|
matches: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
console.log(event.params.guildId, guild);
|
||||||
|
|
||||||
|
if (!guild) return ErrorResponse("NOT_FOUND");
|
||||||
|
|
||||||
|
if (guild.matches.length < 1) return Res("NO_CONTENT", null);
|
||||||
|
|
||||||
|
return Res("OK", {
|
||||||
|
matches: buildMatches(guild.matches),
|
||||||
|
timezone: guild.timezone,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
const guild = await db.query.guilds
|
||||||
|
.findFirst({
|
||||||
|
where: eq(guilds.id, event.params.guildId),
|
||||||
|
with: {
|
||||||
|
matches: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
console.log(event.params.guildId, guild);
|
||||||
|
|
||||||
|
if (!guild) return ErrorResponse("NOT_FOUND");
|
||||||
|
|
||||||
|
const unparsedBody = await new Response(event.request.body).json();
|
||||||
|
|
||||||
|
let body: RequestBody<Path, "post">;
|
||||||
|
try {
|
||||||
|
body = zodMatch.parse(unparsedBody);
|
||||||
|
} catch (e) {
|
||||||
|
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.timezone !== guild.timezone)
|
||||||
|
return ErrorResponse(
|
||||||
|
"BAD_REQUEST",
|
||||||
|
"Match's timezone is different from guild's timezone",
|
||||||
|
);
|
||||||
|
|
||||||
|
await db.insert(matches).values({
|
||||||
|
...body.match,
|
||||||
|
guildId: guild.id,
|
||||||
|
utc_ts: new Date(body.match.utc_ts),
|
||||||
|
});
|
||||||
|
|
||||||
|
return Res("NO_CONTENT", null);
|
||||||
|
};
|
114
src/routes/api/[guildId]/tp_messages.ts
Normal file
114
src/routes/api/[guildId]/tp_messages.ts
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
import { APIEvent } from "@solidjs/start/server/types";
|
||||||
|
import { and, eq } from "drizzle-orm";
|
||||||
|
import db from "~/drizzle";
|
||||||
|
import { guilds, tpMessages } from "~/drizzle/schema";
|
||||||
|
import { BasicAuth } from "~/lib/auth";
|
||||||
|
import { ErrorResponse, Res } from "~/lib/responses";
|
||||||
|
import { zodTpMessages } from "~/lib/zod";
|
||||||
|
import { APIResponse, RequestBody } from "~/types/backend";
|
||||||
|
|
||||||
|
type Path = "/api/{guildId}/tp_messages";
|
||||||
|
|
||||||
|
const DayKeys = ["0", "1", "2", "3", "4", "5", "6"] as const;
|
||||||
|
type DayKeys = (typeof DayKeys)[number];
|
||||||
|
type Messages = Record<DayKeys, string | null>;
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
event: APIEvent,
|
||||||
|
): Promise<APIResponse<Path, "get">> => {
|
||||||
|
switch (event.request.headers.get("authorization")) {
|
||||||
|
case BasicAuth.unencoded:
|
||||||
|
case BasicAuth.encoded:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ErrorResponse("UNAUTHORIZED");
|
||||||
|
}
|
||||||
|
|
||||||
|
const guild = await db.query.guilds.findFirst({
|
||||||
|
where: eq(guilds.id, event.params.guildId),
|
||||||
|
with: {
|
||||||
|
tpMessages: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!guild) return ErrorResponse("NOT_FOUND");
|
||||||
|
|
||||||
|
if (!guild.tpEnabled || !guild.tpChannelId) return Res("NO_CONTENT", null);
|
||||||
|
|
||||||
|
const tpMessages = guild.tpMessages.reduce(
|
||||||
|
(acc, message) => {
|
||||||
|
const day = message.day.toString() as DayKeys;
|
||||||
|
if (!/^[0-6]$/.test(day)) return acc;
|
||||||
|
acc[day] = message.messageId;
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"0": null,
|
||||||
|
"1": null,
|
||||||
|
"2": null,
|
||||||
|
"3": null,
|
||||||
|
"4": null,
|
||||||
|
"5": null,
|
||||||
|
"6": null,
|
||||||
|
} as Messages,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Res("OK", {
|
||||||
|
channelId: guild.tpChannelId,
|
||||||
|
messageIds: tpMessages,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PUT = async (
|
||||||
|
event: APIEvent,
|
||||||
|
): Promise<APIResponse<Path, "put">> => {
|
||||||
|
switch (event.request.headers.get("authorization")) {
|
||||||
|
case BasicAuth.unencoded:
|
||||||
|
case BasicAuth.encoded:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ErrorResponse("UNAUTHORIZED");
|
||||||
|
}
|
||||||
|
|
||||||
|
const guild = await db.query.guilds
|
||||||
|
.findFirst({
|
||||||
|
where: eq(guilds.id, event.params.guildId),
|
||||||
|
with: { tpMessages: true },
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
if (!guild) return ErrorResponse("NOT_FOUND");
|
||||||
|
|
||||||
|
if (!guild.tpEnabled) return ErrorResponse("FORBIDDEN");
|
||||||
|
|
||||||
|
const unparsedBody = await new Response(event.request.body).json();
|
||||||
|
|
||||||
|
let body: RequestBody<Path, "put">;
|
||||||
|
try {
|
||||||
|
body = zodTpMessages.parse(unparsedBody);
|
||||||
|
} catch (e) {
|
||||||
|
return ErrorResponse("BAD_REQUEST", JSON.stringify(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (guild.tpChannelId !== body.channelId)
|
||||||
|
await db
|
||||||
|
.update(guilds)
|
||||||
|
.set({ tpChannelId: body.channelId })
|
||||||
|
.where(eq(guilds.id, guild.id))
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
DayKeys.map(async (dayStr) => {
|
||||||
|
const day = parseInt(dayStr);
|
||||||
|
await db
|
||||||
|
.update(tpMessages)
|
||||||
|
.set({ messageId: body.messageIds[dayStr] })
|
||||||
|
.where(and(eq(tpMessages.guildId, guild.id), eq(tpMessages.day, day)))
|
||||||
|
.execute();
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return Res("NO_CONTENT", null);
|
||||||
|
};
|
|
@ -2,6 +2,7 @@ import { createId } from "@paralleldrive/cuid2";
|
||||||
import { APIEvent } from "@solidjs/start/server/types";
|
import { APIEvent } from "@solidjs/start/server/types";
|
||||||
import { OAuth2RequestError } from "arctic";
|
import { OAuth2RequestError } from "arctic";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
|
import httpStatus from "http-status";
|
||||||
import createClient from "openapi-fetch";
|
import createClient from "openapi-fetch";
|
||||||
import { getCookie, setCookie } from "vinxi/http";
|
import { getCookie, setCookie } from "vinxi/http";
|
||||||
import db from "~/drizzle";
|
import db from "~/drizzle";
|
||||||
|
@ -20,20 +21,20 @@ export async function GET(event: APIEvent): Promise<Response> {
|
||||||
switch (error) {
|
switch (error) {
|
||||||
case "access_denied":
|
case "access_denied":
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 302,
|
status: httpStatus.FOUND,
|
||||||
headers: { Location: "/" },
|
headers: { Location: "/" },
|
||||||
});
|
});
|
||||||
default:
|
default:
|
||||||
console.log("Discord oauth error:", error_description);
|
console.log("Discord oauth error:", error_description);
|
||||||
return new Response(decodeURI(error_description ?? ""), {
|
return new Response(decodeURI(error_description ?? ""), {
|
||||||
status: 400,
|
status: httpStatus.BAD_REQUEST,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const storedState = getCookie("discord_oauth_state") ?? null;
|
const storedState = getCookie("discord_oauth_state") ?? null;
|
||||||
if (!code || !state || !storedState || state !== storedState) {
|
if (!code || !state || !storedState || state !== storedState) {
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 400,
|
status: httpStatus.BAD_REQUEST,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +78,7 @@ export async function GET(event: APIEvent): Promise<Response> {
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 302,
|
status: httpStatus.FOUND,
|
||||||
headers: { Location: "/config" },
|
headers: { Location: "/config" },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -112,7 +113,7 @@ export async function GET(event: APIEvent): Promise<Response> {
|
||||||
sessionCookie.attributes,
|
sessionCookie.attributes,
|
||||||
);
|
);
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 302,
|
status: httpStatus.FOUND,
|
||||||
headers: { Location: "/config" },
|
headers: { Location: "/config" },
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -120,13 +121,13 @@ export async function GET(event: APIEvent): Promise<Response> {
|
||||||
if (e instanceof OAuth2RequestError) {
|
if (e instanceof OAuth2RequestError) {
|
||||||
// invalid code
|
// invalid code
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 400,
|
status: httpStatus.BAD_REQUEST,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
console.error("Unknown error on callback.");
|
console.error("Unknown error on callback.");
|
||||||
console.error(e);
|
console.error(e);
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 500,
|
status: httpStatus.INTERNAL_SERVER_ERROR,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { APIEvent } from "@solidjs/start/server/types";
|
import { APIEvent } from "@solidjs/start/server/types";
|
||||||
import { generateState } from "arctic";
|
import { generateState } from "arctic";
|
||||||
|
import httpStatus from "http-status";
|
||||||
import { setCookie } from "vinxi/http";
|
import { setCookie } from "vinxi/http";
|
||||||
import { discord } from "~/lib/auth";
|
import { discord } from "~/lib/auth";
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ export async function GET(event: APIEvent) {
|
||||||
});
|
});
|
||||||
|
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 302,
|
status: httpStatus.FOUND,
|
||||||
headers: { Location: url.toString() },
|
headers: { Location: url.toString() },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { APIEvent } from "@solidjs/start/server/types";
|
import { APIEvent } from "@solidjs/start/server/types";
|
||||||
|
import httpStatus from "http-status";
|
||||||
import { appendHeader } from "vinxi/http";
|
import { appendHeader } from "vinxi/http";
|
||||||
import { lucia } from "~/lib/auth";
|
import { lucia } from "~/lib/auth";
|
||||||
|
|
||||||
|
@ -13,7 +14,7 @@ export const GET = async (event: APIEvent) => {
|
||||||
lucia.createBlankSessionCookie().serialize(),
|
lucia.createBlankSessionCookie().serialize(),
|
||||||
);
|
);
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 302,
|
status: httpStatus.FOUND,
|
||||||
headers: { Location: "/" },
|
headers: { Location: "/" },
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
35
src/routes/api/boot.ts
Normal file
35
src/routes/api/boot.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import { APIEvent } from "@solidjs/start/server/types";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import db from "~/drizzle";
|
||||||
|
import { guilds } from "~/drizzle/schema";
|
||||||
|
import { BasicAuth } from "~/lib/auth";
|
||||||
|
import { buildConfig } from "~/lib/responseBuilders";
|
||||||
|
import { ErrorResponse, Res } from "~/lib/responses";
|
||||||
|
import { APIResponse } from "~/types/backend";
|
||||||
|
|
||||||
|
type Path = "/api/boot";
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
event: APIEvent,
|
||||||
|
): Promise<APIResponse<Path, "get">> => {
|
||||||
|
switch (event.request.headers.get("authorization")) {
|
||||||
|
case BasicAuth.unencoded:
|
||||||
|
case BasicAuth.encoded:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ErrorResponse("UNAUTHORIZED");
|
||||||
|
}
|
||||||
|
|
||||||
|
const guildQuery = await db.query.guilds
|
||||||
|
.findMany({
|
||||||
|
where: eq(guilds.id, event.params.guildId),
|
||||||
|
with: { tpMessages: true, matches: true },
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
return Res(
|
||||||
|
"OK",
|
||||||
|
guildQuery.map((e) => buildConfig(e)),
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,61 +0,0 @@
|
||||||
import { APIEvent } from "@solidjs/start/server/types";
|
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import db from "~/drizzle";
|
|
||||||
import { guilds } from "~/drizzle/schema";
|
|
||||||
|
|
||||||
export const GET = async ({ params }: APIEvent) => {
|
|
||||||
if (params.guildId === "boot") {
|
|
||||||
const guilds = await db.query.guilds
|
|
||||||
.findMany({
|
|
||||||
with: {
|
|
||||||
timePlanning: { with: { messages: true } },
|
|
||||||
matches: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
return { guilds };
|
|
||||||
}
|
|
||||||
|
|
||||||
const guild = await db.query.guilds
|
|
||||||
.findFirst({
|
|
||||||
where: eq(guilds.id, params.guildId),
|
|
||||||
with: {
|
|
||||||
timePlanning: { with: { messages: true } },
|
|
||||||
matches: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
if (!guild)
|
|
||||||
return new Response(JSON.stringify({ error: "No such guild found." }), {
|
|
||||||
status: 404,
|
|
||||||
});
|
|
||||||
|
|
||||||
return guild;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const DELETE = async ({ params }: APIEvent) => {
|
|
||||||
const guildQuery = await db.query.guilds
|
|
||||||
.findFirst({
|
|
||||||
where: eq(guilds.id, params.guildId),
|
|
||||||
with: {
|
|
||||||
timePlanning: { with: { messages: true } },
|
|
||||||
matches: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
if (!guildQuery)
|
|
||||||
return new Response(JSON.stringify({ error: "No such guild found." }), {
|
|
||||||
status: 404,
|
|
||||||
});
|
|
||||||
|
|
||||||
const guild = await db
|
|
||||||
.delete(guilds)
|
|
||||||
.where(eq(guilds.id, params.guildId))
|
|
||||||
.returning()
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
return guild;
|
|
||||||
};
|
|
|
@ -1,24 +0,0 @@
|
||||||
import { APIEvent } from "@solidjs/start/server/types";
|
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import db from "~/drizzle";
|
|
||||||
import { guilds } from "~/drizzle/schema";
|
|
||||||
|
|
||||||
export const PUT = async ({ params }: APIEvent) => {
|
|
||||||
const guild = await db.query.guilds
|
|
||||||
.findFirst({
|
|
||||||
where: eq(guilds.id, params.guildId),
|
|
||||||
with: {
|
|
||||||
timePlanning: { with: { messages: true } },
|
|
||||||
matches: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
if (!guild)
|
|
||||||
return new Response(JSON.stringify({ error: "No such guild found." }), {
|
|
||||||
status: 404,
|
|
||||||
});
|
|
||||||
|
|
||||||
return "TODO";
|
|
||||||
// return guild.timePlanning;
|
|
||||||
};
|
|
|
@ -1,24 +0,0 @@
|
||||||
import { APIEvent } from "@solidjs/start/server/types";
|
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import db from "~/drizzle";
|
|
||||||
import { guilds } from "~/drizzle/schema";
|
|
||||||
|
|
||||||
export const POST = async ({ params }: APIEvent) => {
|
|
||||||
const guild = await db.query.guilds
|
|
||||||
.findFirst({
|
|
||||||
where: eq(guilds.id, params.guildId),
|
|
||||||
with: {
|
|
||||||
timePlanning: { with: { messages: true } },
|
|
||||||
matches: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
if (!guild)
|
|
||||||
return new Response(JSON.stringify({ error: "No such guild found." }), {
|
|
||||||
status: 404,
|
|
||||||
});
|
|
||||||
|
|
||||||
return "TODO";
|
|
||||||
// return guild.timePlanning;
|
|
||||||
};
|
|
|
@ -1,24 +0,0 @@
|
||||||
import { APIEvent } from "@solidjs/start/server/types";
|
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import db from "~/drizzle";
|
|
||||||
import { guilds } from "~/drizzle/schema";
|
|
||||||
|
|
||||||
export const GET = async ({ params }: APIEvent) => {
|
|
||||||
const guild = await db.query.guilds
|
|
||||||
.findFirst({
|
|
||||||
where: eq(guilds.id, params.guildId),
|
|
||||||
with: {
|
|
||||||
timePlanning: { with: { messages: true } },
|
|
||||||
matches: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
if (!guild)
|
|
||||||
return new Response(JSON.stringify({ error: "No such guild found." }), {
|
|
||||||
status: 404,
|
|
||||||
});
|
|
||||||
|
|
||||||
return "TODO";
|
|
||||||
// return guild.timePlanning;
|
|
||||||
};
|
|
|
@ -1,28 +0,0 @@
|
||||||
import { APIEvent } from "@solidjs/start/server/types";
|
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import db from "~/drizzle";
|
|
||||||
import { guilds } from "~/drizzle/schema";
|
|
||||||
|
|
||||||
export const GET = async ({ params }: APIEvent) => {
|
|
||||||
const guild = await db.query.guilds
|
|
||||||
.findFirst({
|
|
||||||
where: eq(guilds.id, params.guildId),
|
|
||||||
with: {
|
|
||||||
timePlanning: { with: { messages: true } },
|
|
||||||
matches: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
if (!guild)
|
|
||||||
return new Response(JSON.stringify({ error: "No such guild found." }), {
|
|
||||||
status: 404,
|
|
||||||
});
|
|
||||||
|
|
||||||
return "TODO";
|
|
||||||
// return guild.timePlanning;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const PUT = async () => {
|
|
||||||
return "TODO";
|
|
||||||
};
|
|
|
@ -1,14 +0,0 @@
|
||||||
import db from "~/drizzle";
|
|
||||||
|
|
||||||
export const GET = async () => {
|
|
||||||
const guilds = await db.query.guilds
|
|
||||||
.findMany({
|
|
||||||
with: {
|
|
||||||
timePlanning: { with: { messages: true } },
|
|
||||||
matches: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
return { guilds };
|
|
||||||
};
|
|
15
src/types/authjs.d.ts
vendored
15
src/types/authjs.d.ts
vendored
|
@ -1,15 +0,0 @@
|
||||||
import { DefaultSession as DSession } from "@auth/core/types"
|
|
||||||
|
|
||||||
declare module "@auth/core/types" {
|
|
||||||
/**
|
|
||||||
* Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context
|
|
||||||
*/
|
|
||||||
interface Session extends DSession {
|
|
||||||
user?: {
|
|
||||||
id: string
|
|
||||||
name?: string | null
|
|
||||||
email?: string | null
|
|
||||||
image?: string | null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
70
src/types/backend.d.ts
vendored
Normal file
70
src/types/backend.d.ts
vendored
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import { HttpStatus } from "http-status";
|
||||||
|
import { paths } from "./liljudd";
|
||||||
|
|
||||||
|
export type MyPaths = keyof paths;
|
||||||
|
|
||||||
|
export type Methods<Path extends MyPaths> = keyof paths[Path];
|
||||||
|
|
||||||
|
export type Responses<
|
||||||
|
Path extends MyPaths,
|
||||||
|
Method extends Methods<Path>,
|
||||||
|
> = "responses" extends keyof paths[Path][Method]
|
||||||
|
? paths[Path][Method]["responses"]
|
||||||
|
: never;
|
||||||
|
|
||||||
|
type StatusCodes<P extends MyPaths, M extends Methods<P>> = {
|
||||||
|
[CodeName in keyof HttpStatus]: HttpStatus[CodeName] extends number
|
||||||
|
? HttpStatus[CodeName] extends keyof Responses<P, M>
|
||||||
|
? CodeName
|
||||||
|
: never
|
||||||
|
: never;
|
||||||
|
}[keyof HttpStatus];
|
||||||
|
|
||||||
|
export type ResponseSchemas<
|
||||||
|
Path extends MyPaths,
|
||||||
|
Method extends Methods<Path>,
|
||||||
|
Code extends StatusCodes<Path, Method>,
|
||||||
|
> = Code extends keyof HttpStatus
|
||||||
|
? HttpStatus[Code] extends keyof Responses<Path, Method>
|
||||||
|
? "content" extends keyof Responses<Path, Method>[HttpStatus[Code]]
|
||||||
|
? "application/json" extends keyof Responses<
|
||||||
|
Path,
|
||||||
|
Method
|
||||||
|
>[HttpStatus[Code]]["content"]
|
||||||
|
? Responses<
|
||||||
|
Path,
|
||||||
|
Method
|
||||||
|
>[HttpStatus[Code]]["content"]["application/json"] extends never
|
||||||
|
? null
|
||||||
|
: Responses<
|
||||||
|
Path,
|
||||||
|
Method
|
||||||
|
>[HttpStatus[Code]]["content"]["application/json"]
|
||||||
|
: never
|
||||||
|
: never
|
||||||
|
: never
|
||||||
|
: never;
|
||||||
|
|
||||||
|
export type Parameters<
|
||||||
|
Path extends MyPaths,
|
||||||
|
Method extends Methods<Path>,
|
||||||
|
> = "parameters" extends keyof paths[Path][Method]
|
||||||
|
? "path" extends keyof paths[Path][Method]["parameters"]
|
||||||
|
? paths[Path][Method]["parameters"]["path"]
|
||||||
|
: never
|
||||||
|
: never;
|
||||||
|
|
||||||
|
export type RequestBody<
|
||||||
|
Path extends MyPaths,
|
||||||
|
Method extends Methods<Path>,
|
||||||
|
> = "requestBody" extends keyof paths[Path][Method]
|
||||||
|
? "content" extends keyof paths[Path][Method]["requestBody"]
|
||||||
|
? "application/json" extends keyof paths[Path][Method]["requestBody"]["content"]
|
||||||
|
? paths[Path][Method]["requestBody"]["content"]["application/json"]
|
||||||
|
: never
|
||||||
|
: never
|
||||||
|
: never;
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
export interface APIResponse<Path extends MyPaths, Method extends Methods<Path>>
|
||||||
|
extends Response {}
|
0
src/global.d.ts → src/types/global.d.ts
vendored
0
src/global.d.ts → src/types/global.d.ts
vendored
325
src/types/liljudd.d.ts
vendored
325
src/types/liljudd.d.ts
vendored
|
@ -5,24 +5,48 @@
|
||||||
|
|
||||||
|
|
||||||
export interface paths {
|
export interface paths {
|
||||||
"/api/config/{guildId}": {
|
"/api/boot": {
|
||||||
/**
|
/**
|
||||||
* Find guild config by ID
|
* Retrieve all guild's configs
|
||||||
* @description Returns a single guild config
|
* @description Returns all guild's configs.
|
||||||
|
*/
|
||||||
|
get: operations["getGuildsForBoot"];
|
||||||
|
};
|
||||||
|
"/api/{guildId}/config": {
|
||||||
|
/**
|
||||||
|
* Find a guild's config by ID
|
||||||
|
* @description Returns a single guild's config.
|
||||||
*/
|
*/
|
||||||
get: operations["getGuildById"];
|
get: operations["getGuildById"];
|
||||||
/**
|
/**
|
||||||
* Deletes a guild config by ID
|
* Deletes a guild's config by ID
|
||||||
* @description Delete a guild's config
|
* @description Delete a guild's config when the bot is removed from the guild.
|
||||||
*/
|
*/
|
||||||
delete: operations["deleteGuildById"];
|
delete: operations["deleteGuildById"];
|
||||||
};
|
};
|
||||||
"/api/tp_messages/{guildId}": {
|
"/api/{guildId}/tp_messages": {
|
||||||
/**
|
/**
|
||||||
* Find guild by ID for it's tp_messages
|
* Find the tp_messages of guild by ID
|
||||||
* @description Returns tp_messages for a guild
|
* @description Returns tp_messages for a guild
|
||||||
*/
|
*/
|
||||||
get: operations["getTp_messagesOfGuildById"];
|
get: operations["getTp_messagesOfGuildById"];
|
||||||
|
/**
|
||||||
|
* Put new message IDs for tp_messages of guild by ID
|
||||||
|
* @description Returns tp_messages for a guild
|
||||||
|
*/
|
||||||
|
put: operations["putTp_messagesOfGuildById"];
|
||||||
|
};
|
||||||
|
"/api/{guildId}/matches": {
|
||||||
|
/**
|
||||||
|
* Find all matches of guild by ID
|
||||||
|
* @description Returns tp_messages for a guild
|
||||||
|
*/
|
||||||
|
get: operations["getMatchesOfGuildById"];
|
||||||
|
/**
|
||||||
|
* Save a new created match of guild by ID
|
||||||
|
* @description Returns tp_messages for a guild
|
||||||
|
*/
|
||||||
|
post: operations["postMatchOfGuildById"];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,66 +56,124 @@ export interface components {
|
||||||
schemas: {
|
schemas: {
|
||||||
guildConfig: {
|
guildConfig: {
|
||||||
/**
|
/**
|
||||||
* Format: varchar(19)
|
* Format: varchar(20)
|
||||||
* @example 1234567890123456789
|
* @example 1234567890123456789
|
||||||
*/
|
*/
|
||||||
guildID?: string;
|
guildId: string;
|
||||||
features?: {
|
|
||||||
time_planning?: {
|
|
||||||
/**
|
/**
|
||||||
* Format: varchar(19)
|
* Format: text
|
||||||
* @example 1234567890123456789
|
* @example Europe/Berlin
|
||||||
*/
|
*/
|
||||||
channelID?: string;
|
timezone: string;
|
||||||
/** @example 0 0 1 * * * 60o 1w */
|
features: {
|
||||||
cron?: string;
|
timePlanning: {
|
||||||
|
enabled: boolean;
|
||||||
/**
|
/**
|
||||||
* Format: varchar(19)
|
* Format: varchar(20)
|
||||||
* @example 1234567890123456789
|
* @example 1234567890123456789
|
||||||
*/
|
*/
|
||||||
isAvailableRoleId?: string;
|
channelId: string | null;
|
||||||
|
/** @example 0 */
|
||||||
|
targetMinute: number;
|
||||||
|
/** @example 1 */
|
||||||
|
targetHour: number;
|
||||||
|
/** @example 1 */
|
||||||
|
targetDay: number;
|
||||||
|
roles: {
|
||||||
|
enabled: boolean;
|
||||||
/**
|
/**
|
||||||
* Format: varchar(19)
|
* Format: varchar(20)
|
||||||
* @example 1234567890123456789
|
* @example 1234567890123456789
|
||||||
*/
|
*/
|
||||||
wantsToBeNotifieRoledId?: string;
|
isAvailableRoleId: string | null;
|
||||||
|
/**
|
||||||
|
* Format: varchar(20)
|
||||||
|
* @example 1234567890123456789
|
||||||
|
*/
|
||||||
|
wantsToBeNotifieRoledId: string | null;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
matches?: components["schemas"]["match"][];
|
};
|
||||||
|
matches: components["schemas"]["match"][];
|
||||||
|
checksum: string;
|
||||||
};
|
};
|
||||||
match: {
|
match: {
|
||||||
/**
|
/**
|
||||||
* Format: varchar(19)
|
* Format: varcharq(20)
|
||||||
* @example 1234567890123456789
|
* @example 1234567890123456789
|
||||||
*/
|
*/
|
||||||
channelID?: string;
|
channelId: string;
|
||||||
/**
|
/**
|
||||||
* Format: varchar(50)
|
* Format: varchar(50)
|
||||||
* @example Scrim
|
* @example Scrim
|
||||||
*/
|
*/
|
||||||
matchType?: string;
|
matchType: string;
|
||||||
/**
|
/**
|
||||||
* Format: varchar(19)
|
* Format: varchar(20)
|
||||||
* @example 1234567890123456789
|
* @example 1234567890123456789
|
||||||
*/
|
*/
|
||||||
createrId?: string;
|
createrId: string;
|
||||||
/**
|
/**
|
||||||
* Format: varchar(19)
|
* Format: varchar(20)
|
||||||
* @example 1234567890123456789
|
* @example 1234567890123456789
|
||||||
*/
|
*/
|
||||||
roleId?: string;
|
roleId: string;
|
||||||
/**
|
/**
|
||||||
* Format: varchar(100)
|
* Format: varchar(100)
|
||||||
* @example ?
|
* @example ?
|
||||||
*/
|
*/
|
||||||
opponentName?: string;
|
opponentName: string;
|
||||||
/**
|
/**
|
||||||
* Format: varchar(19)
|
* Format: varchar(20)
|
||||||
* @example 1234567890123456789
|
* @example 1234567890123456789
|
||||||
*/
|
*/
|
||||||
messsageId?: string;
|
messageId: string;
|
||||||
/** @example 0 0 1 5 2 2023 60o */
|
/** @example 2020-01-01T00:00:00Z */
|
||||||
cron?: string;
|
utc_ts: string;
|
||||||
|
};
|
||||||
|
tp_messages: {
|
||||||
|
/**
|
||||||
|
* Format: varchar(20)
|
||||||
|
* @example 1234567890123456789
|
||||||
|
*/
|
||||||
|
channelId: string;
|
||||||
|
messageIds: {
|
||||||
|
/**
|
||||||
|
* Format: varchar(20)
|
||||||
|
* @example 1234567890123456789
|
||||||
|
*/
|
||||||
|
0: string | null;
|
||||||
|
/**
|
||||||
|
* Format: varchar(20)
|
||||||
|
* @example 1234567890123456789
|
||||||
|
*/
|
||||||
|
1: string | null;
|
||||||
|
/**
|
||||||
|
* Format: varchar(20)
|
||||||
|
* @example 1234567890123456789
|
||||||
|
*/
|
||||||
|
2: string | null;
|
||||||
|
/**
|
||||||
|
* Format: varchar(20)
|
||||||
|
* @example 1234567890123456789
|
||||||
|
*/
|
||||||
|
3: string | null;
|
||||||
|
/**
|
||||||
|
* Format: varchar(20)
|
||||||
|
* @example 1234567890123456789
|
||||||
|
*/
|
||||||
|
4: string | null;
|
||||||
|
/**
|
||||||
|
* Format: varchar(20)
|
||||||
|
* @example 1234567890123456789
|
||||||
|
*/
|
||||||
|
5: string | null;
|
||||||
|
/**
|
||||||
|
* Format: varchar(20)
|
||||||
|
* @example 1234567890123456789
|
||||||
|
*/
|
||||||
|
6: string | null;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
responses: never;
|
responses: never;
|
||||||
|
@ -108,8 +190,34 @@ export type external = Record<string, never>;
|
||||||
export interface operations {
|
export interface operations {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find guild config by ID
|
* Retrieve all guild's configs
|
||||||
* @description Returns a single guild config
|
* @description Returns all guild's configs.
|
||||||
|
*/
|
||||||
|
getGuildsForBoot: {
|
||||||
|
responses: {
|
||||||
|
/** @description successful operation */
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["guildConfig"][];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Invalid ID supplied */
|
||||||
|
400: {
|
||||||
|
content: never;
|
||||||
|
};
|
||||||
|
/** @description Unauthorized */
|
||||||
|
401: {
|
||||||
|
content: never;
|
||||||
|
};
|
||||||
|
/** @description Guild not found */
|
||||||
|
404: {
|
||||||
|
content: never;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Find a guild's config by ID
|
||||||
|
* @description Returns a single guild's config.
|
||||||
*/
|
*/
|
||||||
getGuildById: {
|
getGuildById: {
|
||||||
parameters: {
|
parameters: {
|
||||||
|
@ -129,6 +237,10 @@ export interface operations {
|
||||||
400: {
|
400: {
|
||||||
content: never;
|
content: never;
|
||||||
};
|
};
|
||||||
|
/** @description Unauthorized */
|
||||||
|
401: {
|
||||||
|
content: never;
|
||||||
|
};
|
||||||
/** @description Guild not found */
|
/** @description Guild not found */
|
||||||
404: {
|
404: {
|
||||||
content: never;
|
content: never;
|
||||||
|
@ -136,8 +248,8 @@ export interface operations {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Deletes a guild config by ID
|
* Deletes a guild's config by ID
|
||||||
* @description Delete a guild's config
|
* @description Delete a guild's config when the bot is removed from the guild.
|
||||||
*/
|
*/
|
||||||
deleteGuildById: {
|
deleteGuildById: {
|
||||||
parameters: {
|
parameters: {
|
||||||
|
@ -155,6 +267,10 @@ export interface operations {
|
||||||
400: {
|
400: {
|
||||||
content: never;
|
content: never;
|
||||||
};
|
};
|
||||||
|
/** @description Unauthorized */
|
||||||
|
401: {
|
||||||
|
content: never;
|
||||||
|
};
|
||||||
/** @description Guild not found */
|
/** @description Guild not found */
|
||||||
404: {
|
404: {
|
||||||
content: never;
|
content: never;
|
||||||
|
@ -162,7 +278,7 @@ export interface operations {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Find guild by ID for it's tp_messages
|
* Find the tp_messages of guild by ID
|
||||||
* @description Returns tp_messages for a guild
|
* @description Returns tp_messages for a guild
|
||||||
*/
|
*/
|
||||||
getTp_messagesOfGuildById: {
|
getTp_messagesOfGuildById: {
|
||||||
|
@ -176,7 +292,7 @@ export interface operations {
|
||||||
/** @description successful operation */
|
/** @description successful operation */
|
||||||
200: {
|
200: {
|
||||||
content: {
|
content: {
|
||||||
"application/json": components["schemas"]["guildConfig"];
|
"application/json": components["schemas"]["tp_messages"];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/** @description Time planning not enabled for this guild */
|
/** @description Time planning not enabled for this guild */
|
||||||
|
@ -187,6 +303,137 @@ export interface operations {
|
||||||
400: {
|
400: {
|
||||||
content: never;
|
content: never;
|
||||||
};
|
};
|
||||||
|
/** @description Unauthorized */
|
||||||
|
401: {
|
||||||
|
content: never;
|
||||||
|
};
|
||||||
|
/** @description Guild not found */
|
||||||
|
404: {
|
||||||
|
content: never;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Put new message IDs for tp_messages of guild by ID
|
||||||
|
* @description Returns tp_messages for a guild
|
||||||
|
*/
|
||||||
|
putTp_messagesOfGuildById: {
|
||||||
|
parameters: {
|
||||||
|
path: {
|
||||||
|
/** @description ID of guild's tp_messages to return */
|
||||||
|
guildId: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Put new message IDs for tp_messages in channel */
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["tp_messages"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** @description successful operation */
|
||||||
|
204: {
|
||||||
|
content: never;
|
||||||
|
};
|
||||||
|
/** @description Invalid ID supplied */
|
||||||
|
400: {
|
||||||
|
content: never;
|
||||||
|
};
|
||||||
|
/** @description Unauthorized */
|
||||||
|
401: {
|
||||||
|
content: never;
|
||||||
|
};
|
||||||
|
/** @description Time planning not enabled for this guild */
|
||||||
|
403: {
|
||||||
|
content: never;
|
||||||
|
};
|
||||||
|
/** @description Guild not found */
|
||||||
|
404: {
|
||||||
|
content: never;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Find all matches of guild by ID
|
||||||
|
* @description Returns tp_messages for a guild
|
||||||
|
*/
|
||||||
|
getMatchesOfGuildById: {
|
||||||
|
parameters: {
|
||||||
|
path: {
|
||||||
|
/** @description ID of guild's tp_messages to return */
|
||||||
|
guildId: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** @description successful operation */
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
matches: components["schemas"]["match"][];
|
||||||
|
/**
|
||||||
|
* Format: text
|
||||||
|
* @example Europe/Berlin
|
||||||
|
*/
|
||||||
|
timezone: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Time planning not enabled for this guild */
|
||||||
|
204: {
|
||||||
|
content: never;
|
||||||
|
};
|
||||||
|
/** @description Invalid ID supplied */
|
||||||
|
400: {
|
||||||
|
content: never;
|
||||||
|
};
|
||||||
|
/** @description Unauthorized */
|
||||||
|
401: {
|
||||||
|
content: never;
|
||||||
|
};
|
||||||
|
/** @description Guild not found */
|
||||||
|
404: {
|
||||||
|
content: never;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Save a new created match of guild by ID
|
||||||
|
* @description Returns tp_messages for a guild
|
||||||
|
*/
|
||||||
|
postMatchOfGuildById: {
|
||||||
|
parameters: {
|
||||||
|
path: {
|
||||||
|
/** @description ID of match's guild to set */
|
||||||
|
guildId: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Save a new created match in channel */
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
match: components["schemas"]["match"];
|
||||||
|
/**
|
||||||
|
* Format: text
|
||||||
|
* @description Has to match guild tz
|
||||||
|
* @example Europe/Berlin
|
||||||
|
*/
|
||||||
|
timezone: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** @description successful operation */
|
||||||
|
204: {
|
||||||
|
content: never;
|
||||||
|
};
|
||||||
|
/** @description Invalid ID supplied */
|
||||||
|
400: {
|
||||||
|
content: never;
|
||||||
|
};
|
||||||
|
/** @description Unauthorized */
|
||||||
|
401: {
|
||||||
|
content: never;
|
||||||
|
};
|
||||||
/** @description Guild not found */
|
/** @description Guild not found */
|
||||||
404: {
|
404: {
|
||||||
content: never;
|
content: never;
|
||||||
|
|
25
src/types/lucia-auth.d.ts
vendored
Normal file
25
src/types/lucia-auth.d.ts
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import { PgColumn, PgTableWithColumns } from "drizzle-orm/pg-core";
|
||||||
|
import { users } from "~/drizzle/schema";
|
||||||
|
import { lucia } from "~/lib/auth";
|
||||||
|
|
||||||
|
declare module "lucia" {
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
interface Register {
|
||||||
|
Lucia: typeof lucia;
|
||||||
|
DatabaseUserAttributes: DatabaseUserAttributes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetColumns<T> =
|
||||||
|
T extends PgTableWithColumns<infer First> ? First["columns"] : never;
|
||||||
|
|
||||||
|
type ExtractDataTypes<T> = {
|
||||||
|
[K in keyof T]: T[K] extends PgColumn<infer DataType, never, never>
|
||||||
|
? DataType["data"]
|
||||||
|
: never;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface DatabaseUserAttributes
|
||||||
|
extends ExtractDataTypes<GetColumns<typeof users>> {
|
||||||
|
warst: string;
|
||||||
|
}
|
Loading…
Reference in a new issue