mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-03-21 18:04:39 -05:00
Delete redundants parts
This commit is contained in:
parent
1c05643de6
commit
e1c05939cb
28
README.md
28
README.md
|
|
@ -27,17 +27,6 @@ You might be able to skip steps 2-4 and use a few pages but most pages need a se
|
|||
|
||||
## .env
|
||||
|
||||
### /server
|
||||
|
||||
| Name | Description | Required |
|
||||
| --------------------- | ----------------------------------------------------------------------------------------------------------- | -------- |
|
||||
| DATABASE_URL | Database connection string. For example mine is currently `postgresql://sendou@localhost:5432/sendou_ink_3` | Yes |
|
||||
| DISCORD_CLIENT_ID | Used for auth. Make an application on [Discord](https://discord.com/developers/applications) | No |
|
||||
| DISCORD_CLIENT_SECRET | See above. | No |
|
||||
| DISCORD_CALLBACK_URL | See above. | No |
|
||||
| FRONTEND_URL | Where frontend is located. Cell | Yes |
|
||||
| NODE_ENV | `development` when developing, `production` in production | Yes |
|
||||
|
||||
### /frontend
|
||||
|
||||
| Name | Description | Required |
|
||||
|
|
@ -63,23 +52,6 @@ frontend/
|
|||
└── utils/ frontend specific utility methods, constants etc.
|
||||
```
|
||||
|
||||
### /server
|
||||
|
||||
This folder contains backend specific code.
|
||||
|
||||
```
|
||||
server/
|
||||
├── index.ts/ entry point
|
||||
├── routes/ route handling logic (controllers)
|
||||
├── middleware/ middlewares that are called before controllers
|
||||
├── services/ methods that talk to the database
|
||||
├── core/ business logic
|
||||
└── prisma/
|
||||
├── migrations/ migrations
|
||||
├── schema.prisma database models
|
||||
└── seed.ts seeding script
|
||||
```
|
||||
|
||||
### /shared
|
||||
|
||||
Utilities, constants etc. that are shared between frontend and backend.
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
import useSWR from "swr";
|
||||
import { Serialized } from "utils/types";
|
||||
|
||||
export function useMySWR<T>(key: string | null) {
|
||||
return useSWR<Serialized<T>>(key);
|
||||
}
|
||||
33
frontend/package-lock.json
generated
33
frontend/package-lock.json
generated
|
|
@ -14,7 +14,6 @@
|
|||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-icons": "^4.3.1",
|
||||
"swr": "^1.0.1",
|
||||
"urql": "^2.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
@ -5863,14 +5862,6 @@
|
|||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dequal": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz",
|
||||
"integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/des.js": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
|
||||
|
|
@ -14512,17 +14503,6 @@
|
|||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/swr": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/swr/-/swr-1.0.1.tgz",
|
||||
"integrity": "sha512-EPQAxSjoD4IaM49rpRHK0q+/NzcwoT8c0/Ylu/u3/6mFj/CWnQVjNJ0MV2Iuw/U+EJSd2TX5czdAwKPYZIG0YA==",
|
||||
"dependencies": {
|
||||
"dequal": "2.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.11.0 || ^17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/symbol-observable": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
||||
|
|
@ -20708,11 +20688,6 @@
|
|||
"integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==",
|
||||
"dev": true
|
||||
},
|
||||
"dequal": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz",
|
||||
"integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug=="
|
||||
},
|
||||
"des.js": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
|
||||
|
|
@ -27493,14 +27468,6 @@
|
|||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"swr": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/swr/-/swr-1.0.1.tgz",
|
||||
"integrity": "sha512-EPQAxSjoD4IaM49rpRHK0q+/NzcwoT8c0/Ylu/u3/6mFj/CWnQVjNJ0MV2Iuw/U+EJSd2TX5czdAwKPYZIG0YA==",
|
||||
"requires": {
|
||||
"dequal": "2.0.2"
|
||||
}
|
||||
},
|
||||
"symbol-observable": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-icons": "^4.3.1",
|
||||
"swr": "^1.0.1",
|
||||
"urql": "^2.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import "./_app.css";
|
|||
|
||||
import { AppProps } from "next/app";
|
||||
import Head from "next/head";
|
||||
import { SWRConfig } from "swr";
|
||||
import { Layout } from "components/layout/Layout";
|
||||
import { globalCss } from "stitches.config";
|
||||
import { Provider, createClient } from "urql";
|
||||
|
|
@ -42,18 +41,9 @@ export default function App(props: AppProps) {
|
|||
/>
|
||||
</Head>
|
||||
<Provider value={client}>
|
||||
<SWRConfig
|
||||
value={{
|
||||
fetcher: (resource, init) =>
|
||||
fetch(process.env.NEXT_PUBLIC_BACKEND_URL + resource, init).then(
|
||||
(res) => res.json()
|
||||
),
|
||||
}}
|
||||
>
|
||||
<Layout>
|
||||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
</SWRConfig>
|
||||
<Layout>
|
||||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
</Provider>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"server",
|
||||
"frontend",
|
||||
"api",
|
||||
"shared"
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
DATABASE_URL=
|
||||
DISCORD_CLIENT_ID=
|
||||
DISCORD_CLIENT_SECRET=
|
||||
DISCORD_CALLBACK_URL=
|
||||
FRONTEND_URL=http://localhost:3000
|
||||
NODE_ENV=development
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
import { config } from "dotenv";
|
||||
config();
|
||||
|
||||
import { App } from "@tinyhttp/app";
|
||||
import { logger } from "@tinyhttp/logger";
|
||||
import { cors } from "@tinyhttp/cors";
|
||||
import passport from "passport";
|
||||
import { Strategy as DiscordStrategy } from "passport-discord";
|
||||
import routes from "./routes/index";
|
||||
import { findUserById, upsertUser } from "./services/user";
|
||||
|
||||
const app = new App();
|
||||
|
||||
const PORT = 3001;
|
||||
|
||||
validateEnvVars();
|
||||
|
||||
passport.use(
|
||||
new DiscordStrategy(
|
||||
{
|
||||
clientID: process.env.DISCORD_CLIENT_ID!,
|
||||
clientSecret: process.env.DISCORD_CLIENT_SECRET!,
|
||||
callbackURL: process.env.DISCORD_CALLBACK_URL!,
|
||||
scope: ["identify", "connections"],
|
||||
},
|
||||
function (_accessToken, refreshToken, loggedInUser, cb) {
|
||||
upsertUser({ loggedInUser, refreshToken: refreshToken })
|
||||
.then((user) => {
|
||||
return cb(null, user);
|
||||
})
|
||||
.catch((err) => cb(err));
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
passport.serializeUser((user, done) => {
|
||||
// @ts-expect-error - Mismatch of types but seems to work fine
|
||||
const id = user?.id;
|
||||
if (typeof id !== "number") {
|
||||
return done(new Error("typeof id is not number"));
|
||||
}
|
||||
|
||||
done(null, id);
|
||||
});
|
||||
|
||||
passport.deserializeUser(async (id, done) => {
|
||||
if (typeof id !== "number") {
|
||||
return done(new Error("typeof id is not number"));
|
||||
}
|
||||
|
||||
const user = await findUserById(id);
|
||||
done(null, user);
|
||||
});
|
||||
|
||||
app
|
||||
.use(logger())
|
||||
.use(cors({ origin: process.env.FRONTEND_URL }))
|
||||
// @ts-expect-error - Mismatch of types but seems to work fine
|
||||
.use(passport.initialize())
|
||||
.get("/auth/discord", passport.authenticate("discord"))
|
||||
.get(
|
||||
"/auth/discord/callback",
|
||||
passport.authenticate("discord", {
|
||||
failureRedirect: "/login",
|
||||
successRedirect: "/",
|
||||
})
|
||||
)
|
||||
.use(routes)
|
||||
.listen(PORT, () =>
|
||||
console.log(`Server ready at: https://localhost:${PORT}`)
|
||||
);
|
||||
|
||||
function validateEnvVars() {
|
||||
if (!process.env.FRONTEND_URL) {
|
||||
throw new Error("Missing env var for setting cors");
|
||||
}
|
||||
|
||||
const logInEnvVars = [
|
||||
"DISCORD_CLIENT_ID",
|
||||
"DISCORD_CLIENT_SECRET",
|
||||
"DISCORD_CALLBACK_URL",
|
||||
].filter((envVar) => !process.env[envVar]);
|
||||
|
||||
if (logInEnvVars.length === 0) return;
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.warn(
|
||||
"Missing env vars for testing logging in:",
|
||||
logInEnvVars.join(", ")
|
||||
);
|
||||
} else {
|
||||
throw new Error("Missing env vars for logging in");
|
||||
}
|
||||
}
|
||||
1685
server/package-lock.json
generated
1685
server/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
|
@ -1,33 +0,0 @@
|
|||
{
|
||||
"name": "@sendou.ink/server",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"dev": "tsm index.ts",
|
||||
"migration:create": "npx prisma migrate dev --create-only",
|
||||
"migration:apply:dev": "npx prisma migrate dev",
|
||||
"migration:apply:prod": "npx prisma migrate deploy",
|
||||
"seed": "npx prisma migrate reset"
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "^3.3.0",
|
||||
"@tinyhttp/app": "^2.0.11",
|
||||
"@tinyhttp/logger": "^1.3.0",
|
||||
"dotenv": "^10.0.0",
|
||||
"passport": "^0.5.0",
|
||||
"passport-discord": "^0.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tinyhttp/cors": "^2.0.0",
|
||||
"@types/node": "^16.11.4",
|
||||
"@types/passport": "^1.0.7",
|
||||
"@types/passport-discord": "^0.1.5",
|
||||
"prisma": "^3.3.0",
|
||||
"ts-node": "^10.4.0",
|
||||
"tsm": "^2.1.2",
|
||||
"typescript": "^4.4.4"
|
||||
},
|
||||
"type": "module",
|
||||
"prisma": {
|
||||
"seed": "node --loader ts-node/esm prisma/seed.ts"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
import pkg from "@prisma/client";
|
||||
const { PrismaClient } = pkg;
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export default prisma;
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
-- CreateEnum
|
||||
CREATE TYPE "Mode" AS ENUM ('TW', 'SZ', 'TC', 'RM', 'CB');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"discordId" TEXT NOT NULL,
|
||||
"discordName" TEXT NOT NULL,
|
||||
"discordDiscriminator" TEXT NOT NULL,
|
||||
"discordAvatar" TEXT,
|
||||
"discordRefreshToken" TEXT NOT NULL,
|
||||
"twitch" TEXT,
|
||||
"twitter" TEXT,
|
||||
"youtubeId" TEXT,
|
||||
"youtubeName" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Organization" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"nameForUrl" TEXT NOT NULL,
|
||||
"ownerId" INTEGER NOT NULL,
|
||||
"discordInvite" TEXT NOT NULL,
|
||||
"twitter" TEXT,
|
||||
|
||||
CONSTRAINT "Organization_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Tournament" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"nameForUrl" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"startTime" TIMESTAMP(3) NOT NULL,
|
||||
"checkInTime" TIMESTAMP(3) NOT NULL,
|
||||
"bannerBackground" TEXT NOT NULL,
|
||||
"bannerTextHSLArgs" TEXT NOT NULL,
|
||||
"organizerId" INTEGER NOT NULL,
|
||||
|
||||
CONSTRAINT "Tournament_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Stage" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"mode" "Mode" NOT NULL,
|
||||
|
||||
CONSTRAINT "Stage_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "_StageToTournament" (
|
||||
"A" INTEGER NOT NULL,
|
||||
"B" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_discordId_key" ON "User"("discordId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Organization_nameForUrl_key" ON "Organization"("nameForUrl");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Organization_ownerId_key" ON "Organization"("ownerId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Tournament_nameForUrl_organizerId_key" ON "Tournament"("nameForUrl", "organizerId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "_StageToTournament_AB_unique" ON "_StageToTournament"("A", "B");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "_StageToTournament_B_index" ON "_StageToTournament"("B");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Organization" ADD CONSTRAINT "Organization_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Tournament" ADD CONSTRAINT "Tournament_organizerId_fkey" FOREIGN KEY ("organizerId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_StageToTournament" ADD FOREIGN KEY ("A") REFERENCES "Stage"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_StageToTournament" ADD FOREIGN KEY ("B") REFERENCES "Tournament"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (i.e. Git)
|
||||
provider = "postgresql"
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
// This is your Prisma schema file,
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model User {
|
||||
id Int @id @default(autoincrement())
|
||||
discordId String @unique
|
||||
discordName String
|
||||
discordDiscriminator String
|
||||
discordAvatar String?
|
||||
discordRefreshToken String
|
||||
twitch String?
|
||||
twitter String?
|
||||
youtubeId String?
|
||||
youtubeName String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
ownedOrganization Organization?
|
||||
}
|
||||
|
||||
model Organization {
|
||||
id Int @id @default(autoincrement())
|
||||
name String
|
||||
/// Name in lower case to show in URL
|
||||
nameForUrl String @unique
|
||||
ownerId Int @unique
|
||||
owner User @relation(fields: [ownerId], references: [id])
|
||||
discordInvite String
|
||||
twitter String?
|
||||
tournaments Tournament[]
|
||||
}
|
||||
|
||||
model Tournament {
|
||||
id Int @id @default(autoincrement())
|
||||
name String
|
||||
/// Name in lower case to show in URL
|
||||
nameForUrl String
|
||||
description String?
|
||||
startTime DateTime
|
||||
checkInTime DateTime
|
||||
/// CSS for tournament banner's background value
|
||||
bannerBackground String
|
||||
/// CSS for tournament banner's color value
|
||||
bannerTextHSLArgs String
|
||||
mapPool Stage[]
|
||||
organizerId Int
|
||||
organizer Organization @relation(fields: [organizerId], references: [id])
|
||||
|
||||
// There might be duplicate nameForUrl's but inside an organization they're unique
|
||||
@@unique([nameForUrl, organizerId])
|
||||
}
|
||||
|
||||
enum Mode {
|
||||
TW
|
||||
SZ
|
||||
TC
|
||||
RM
|
||||
CB
|
||||
}
|
||||
|
||||
model Stage {
|
||||
id Int @id @default(autoincrement())
|
||||
name String
|
||||
mode Mode
|
||||
tournamentMapPools Tournament[]
|
||||
}
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
import pkg from "@prisma/client";
|
||||
const { PrismaClient } = pkg;
|
||||
import { stages as stageList } from "@sendou-ink/shared/constants";
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
const user = await users();
|
||||
const organization = await organizations(user.id);
|
||||
const tournament = await tournaments(organization.id);
|
||||
await stages();
|
||||
await tournamentAddMaps(tournament.id);
|
||||
}
|
||||
|
||||
async function users() {
|
||||
return prisma.user.create({
|
||||
data: {
|
||||
discordDiscriminator: "4059",
|
||||
discordId: "79237403620945920",
|
||||
discordName: "Sendou",
|
||||
discordRefreshToken: "none",
|
||||
twitch: "Sendou",
|
||||
youtubeId: "UCWbJLXByvsfQvTcR4HLPs5Q",
|
||||
youtubeName: "Sendou",
|
||||
discordAvatar: "fcfd65a3bea598905abb9ca25296816b",
|
||||
twitter: "sendouc",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function organizations(userId: number) {
|
||||
return prisma.organization.create({
|
||||
data: {
|
||||
name: "Sendou's Tournaments",
|
||||
discordInvite: "sendou",
|
||||
nameForUrl: "sendou",
|
||||
twitter: "sendouc",
|
||||
ownerId: userId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const modesList = ["TW", "SZ", "TC", "RM", "CB"] as const;
|
||||
|
||||
async function tournaments(organizationId: number) {
|
||||
return prisma.tournament.create({
|
||||
data: {
|
||||
bannerBackground: "linear-gradient(to bottom, #9796f0, #fbc7d4)",
|
||||
bannerTextHSLArgs: "231, 9%, 16%",
|
||||
checkInTime: new Date(2025, 11, 17, 11),
|
||||
startTime: new Date(2025, 11, 17, 12),
|
||||
name: "In The Zone X",
|
||||
nameForUrl: "in-the-zone-x",
|
||||
organizerId: organizationId,
|
||||
description: "In The Zone eXtreme",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function getRandomInt(maxInclusive: number) {
|
||||
let result = -1;
|
||||
|
||||
while (result < 24) {
|
||||
result = Math.floor(Math.random() * maxInclusive) + 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: why this can't be done while creating?
|
||||
async function tournamentAddMaps(id: number) {
|
||||
const ids = Array.from(
|
||||
new Set(new Array(24).fill(null).map(() => ({ id: getRandomInt(115) })))
|
||||
);
|
||||
|
||||
return prisma.tournament.update({
|
||||
where: { id },
|
||||
data: {
|
||||
mapPool: {
|
||||
connect: ids,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function stages() {
|
||||
return prisma.stage.createMany({
|
||||
data: modesList.flatMap((mode) => {
|
||||
return stageList.map((name) => {
|
||||
return {
|
||||
name,
|
||||
mode,
|
||||
};
|
||||
});
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
import { App } from "@tinyhttp/app";
|
||||
import tournament from "./tournaments.routes";
|
||||
|
||||
const routes = new App();
|
||||
|
||||
routes.use("/tournaments", tournament);
|
||||
|
||||
export default routes;
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
import { App } from "@tinyhttp/app";
|
||||
import { findTournamentByNameForUrl } from "../services/tournament";
|
||||
import type { GetTournamentByOrganizationAndName } from "@sendou-ink/api";
|
||||
|
||||
const app = new App();
|
||||
|
||||
app.get("/:organization/:tournament", async (req, res) => {
|
||||
const { organization, tournament } = req.params;
|
||||
const tournamentFromDB: GetTournamentByOrganizationAndName | undefined =
|
||||
await findTournamentByNameForUrl({
|
||||
organizationNameForUrl: organization,
|
||||
tournamentNameForUrl: tournament,
|
||||
});
|
||||
|
||||
if (!tournamentFromDB) return res.sendStatus(404);
|
||||
|
||||
res.json(tournamentFromDB);
|
||||
});
|
||||
|
||||
export default app;
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
import prisma from "../prisma/client";
|
||||
|
||||
export async function findTournamentByNameForUrl({
|
||||
organizationNameForUrl,
|
||||
tournamentNameForUrl,
|
||||
}: {
|
||||
organizationNameForUrl: string;
|
||||
tournamentNameForUrl: string;
|
||||
}) {
|
||||
const tournaments = await prisma.tournament.findMany({
|
||||
where: {
|
||||
nameForUrl: tournamentNameForUrl.toLowerCase(),
|
||||
},
|
||||
select: {
|
||||
name: true,
|
||||
description: true,
|
||||
startTime: true,
|
||||
checkInTime: true,
|
||||
bannerBackground: true,
|
||||
bannerTextHSLArgs: true,
|
||||
organizer: {
|
||||
select: {
|
||||
name: true,
|
||||
discordInvite: true,
|
||||
twitter: true,
|
||||
nameForUrl: true,
|
||||
},
|
||||
},
|
||||
mapPool: {
|
||||
select: {
|
||||
mode: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const result = tournaments.find(
|
||||
(tournament) =>
|
||||
tournament.organizer.nameForUrl === organizationNameForUrl.toLowerCase()
|
||||
);
|
||||
|
||||
if (!result) return result;
|
||||
|
||||
result.organizer.twitter = twitterToUrl(result.organizer.twitter);
|
||||
result.organizer.discordInvite = discordInviteToUrl(
|
||||
result.organizer.discordInvite
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function twitterToUrl(twitter: string | null) {
|
||||
if (!twitter) return twitter;
|
||||
|
||||
return `https://twitter.com/${twitter}`;
|
||||
}
|
||||
|
||||
function discordInviteToUrl(discordInvite: string) {
|
||||
return `https://discord.com/invite/${discordInvite}`;
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
import prisma from "../prisma/client";
|
||||
import type { Strategy as DiscordStrategy } from "passport-discord";
|
||||
|
||||
export async function upsertUser({
|
||||
loggedInUser,
|
||||
refreshToken,
|
||||
}: {
|
||||
loggedInUser: DiscordStrategy.Profile;
|
||||
refreshToken: string;
|
||||
}) {
|
||||
return prisma.user.upsert({
|
||||
create: {
|
||||
discordId: loggedInUser.id,
|
||||
discordName: loggedInUser.username,
|
||||
discordDiscriminator: loggedInUser.discriminator,
|
||||
discordAvatar: loggedInUser.avatar,
|
||||
discordRefreshToken: refreshToken,
|
||||
...parseConnections(loggedInUser.connections),
|
||||
},
|
||||
update: {
|
||||
discordName: loggedInUser.username,
|
||||
discordDiscriminator: loggedInUser.discriminator,
|
||||
discordAvatar: loggedInUser.avatar,
|
||||
},
|
||||
where: {
|
||||
discordId: loggedInUser.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function parseConnections(
|
||||
connections: DiscordStrategy.ConnectionInfo[] | undefined
|
||||
) {
|
||||
if (!connections) return null;
|
||||
|
||||
const result: {
|
||||
twitch?: string;
|
||||
twitter?: string;
|
||||
youtubeId?: string;
|
||||
youtubeName?: string;
|
||||
} = {};
|
||||
|
||||
for (const connection of connections) {
|
||||
if (connection.visibility !== 1 || !connection.verified) continue;
|
||||
|
||||
switch (connection.type) {
|
||||
case "twitch":
|
||||
result.twitch = connection.name;
|
||||
break;
|
||||
case "twitter":
|
||||
result.twitter = connection.name;
|
||||
break;
|
||||
case "youtube":
|
||||
result.youtubeId = connection.id;
|
||||
result.youtubeName = connection.name;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function findUserById(id: number) {
|
||||
return prisma.user.findUnique({ where: { id } });
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES6",
|
||||
"module": "ESNext",
|
||||
"sourceMap": true,
|
||||
"outDir": "dist",
|
||||
"strict": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUnusedParameters": true,
|
||||
"noUnusedLocals": true,
|
||||
"lib": ["esnext"],
|
||||
"esModuleInterop": true,
|
||||
"moduleResolution": "node",
|
||||
"baseUrl": "."
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user