From 6aff5751c69a0df1431c01bdcdc644b27ecbf8c6 Mon Sep 17 00:00:00 2001 From: dvelo <52332868+DeveloLongScript@users.noreply.github.com> Date: Fri, 4 Oct 2024 21:06:02 -0500 Subject: [PATCH] release: 1.3.2 --- CONTRIBUTING.md | 24 +- biome.json | 4 + cron/src/index.ts | 13 +- next.config.mjs | 1 - package.json | 1 + src/components/ColorProvider.tsx | 2 +- src/components/FavoritesView.tsx | 10 +- src/components/docs/Sidebar.tsx | 2 +- src/config/version.tsx | 623 +++++++++++----------- src/lib/linear.ts | 29 + src/pages/api/inngest.ts | 514 +++--------------- src/pages/api/v0/account-sl/change.ts | 1 + src/pages/api/v0/achievements/[server].ts | 20 +- src/pages/api/v1/death-webhook.ts | 28 +- yarn.lock | 34 +- 15 files changed, 519 insertions(+), 787 deletions(-) create mode 100644 src/lib/linear.ts diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 321990f..afd8312 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,17 +30,17 @@ The primary stack for MHSF is Next.js, a React framework, which you can start by ## Clerk If you want to test out accounts, [you must create an Clerk key from their website.](https://clerk.com) Set the following variables in the .env.local file: -```env +```dotenv # Clerk -NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY= -CLERK_SECRET_KEY= -IS_AUTH=true +NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="pk_..." +CLERK_SECRET_KEY="sk_..." +IS_AUTH="true" ``` ## MongoDB We use [Atlas](https://www.mongodb.com/atlas) to host our MongoDB database, but you do need one. Add the following to your .env.local with your database: -```env -MONGO_DB= +```dotenv +MONGO_DB="mongodb+srv://..." ``` ## Smaller things (for production-ready servers) @@ -63,6 +63,18 @@ yarn run build > You must have a `.env.local` with a MongoDB database (same `MONGO_DB` key) in the previous directory (for monorepo like management) running without Docker, and > the same `.env.local` *but in the same directory when* using Docker. +### Reporting +Reporting inside MHSF uses [Linear](https://linear.app). Create an API key inside a team, and add it to the `LINEAR` +key inside of `.env.local` +```dotenv +LINEAR="ln_api_..." +``` +MHSF will start adding issues automatically, displaying all information +about a server & the user reporting. + +For more information about Linear's authentication, refer to the [API +documentation](https://developers.linear.app/docs/graphql/working-with-the-graphql-api#personal-api-keys). + ### Inngest Inngest also runs periodic tasks like Cron, but has less important tasks that may occur. Create an account on Inngest, or just use the dev server. Do the following tasks and set the endpoint to `/api/inngest` diff --git a/biome.json b/biome.json index f51a068..0f1f370 100644 --- a/biome.json +++ b/biome.json @@ -4,6 +4,10 @@ "rules": { "style": { "useTemplate": "off" + }, + "suspicious": { + "noExplicitAny": "off", + "noDoubleEquals": "warn" } } } diff --git a/cron/src/index.ts b/cron/src/index.ts index 3a7023b..113788f 100644 --- a/cron/src/index.ts +++ b/cron/src/index.ts @@ -7,33 +7,32 @@ console.log(chalk.yellow(chalk.bold("MHSF crontab scripts"))); console.log(chalk.yellow(chalk.bold("by dvelo - licensed under MIT license"))); console.log(); -import { MongoClient, WithId } from "mongodb"; +import { MongoClient, type WithId } from "mongodb"; import { config } from "dotenv"; -import { +import type { OnlineServer, OnlineServerExtended, ServerResponse, } from "./types/mh-server.js"; import { CronJob } from "cron"; -import { Achievement } from "./types/achievement.js"; +import type { Achievement } from "./types/achievement.js"; // set-up config config({ path: process.env.MHC_DOCKER != "true" ? "../.env.local" : "./.env.local", }); -let mongo = new MongoClient(process.env.MONGO_DB as string); +const mongo = new MongoClient(process.env.MONGO_DB as string); const SUCCESS = chalk.green("SUCCESS"); const ERROR = chalk.red("ERROR"); -const WARN = chalk.red("WARN"); const INFO = chalk.blueBright("INFO"); console.log(INFO, "Starting cron job #1"); CronJob.from({ cronTime: "*/30 * * * *", - onTick: function () { + onTick: () => { periodicCronJob().catch((e) => { console.log(chalk.red("[CRON] " + ERROR + " Error while running: ")); console.error(e); @@ -46,7 +45,7 @@ CronJob.from({ console.log(INFO, "Starting cron job #2"); CronJob.from({ cronTime: "0 */12 * * *", - onTick: function () { + onTick: () => { achievementTask().catch((e) => { console.log(chalk.red("[CRON] " + ERROR + " Error while running: ")); console.error(e); diff --git a/next.config.mjs b/next.config.mjs index 063ead9..b5c3c5b 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -12,7 +12,6 @@ const nextConfig = { }, async redirects() { return [ - // Basic redirect { source: '/docs', destination: '/docs/getting-started', diff --git a/package.json b/package.json index db5231b..77b1f8d 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@biomejs/biome": "^1.8.3", "@clerk/nextjs": "^5.1.3", "@emotion/is-prop-valid": "^1.3.0", + "@linear/sdk": "^31.0.0", "@monaco-editor/react": "^4.6.0", "@radix-ui/react-hover-card": "^1.1.1", "@radix-ui/react-icons": "^1.3.0", diff --git a/src/components/ColorProvider.tsx b/src/components/ColorProvider.tsx index 227fd92..fbc0b3c 100644 --- a/src/components/ColorProvider.tsx +++ b/src/components/ColorProvider.tsx @@ -20,7 +20,7 @@ export default function ColorProvider({ getCustomization(server).then((v) => setColor(v != null ? v.colorScheme : "zinc") ); - else setColor(fetch != null ? fetch.colorScheme : "zinc"); + else setColor(fetch.colorScheme); }, []); return
{children}
; diff --git a/src/components/FavoritesView.tsx b/src/components/FavoritesView.tsx index 827513e..d03286c 100644 --- a/src/components/FavoritesView.tsx +++ b/src/components/FavoritesView.tsx @@ -2,7 +2,7 @@ import { useState } from "react"; import { Spinner } from "./ui/spinner"; import { Card, CardHeader, CardTitle } from "./ui/card"; -import { ServerResponse } from "@/lib/types/mh-server"; +import type { ServerResponse } from "@/lib/types/mh-server"; import { useEffectOnce } from "@/lib/useEffectOnce"; import { Button } from "./ui/button"; import { Copy, Layers, XIcon } from "lucide-react"; @@ -26,16 +26,16 @@ export default function FavoritesView() { (b) => b.json().then((c) => { num++; - var apiClone = apiFavorites; + const apiClone = apiFavorites; apiClone.push(c.server); setApiFavorites(apiClone); - if (num == d.length) { + if (num === d.length) { setLoading(false); } }) ); }); - if (d.length == 0) setLoading(false); + if (d.length === 0) setLoading(false); }); }); @@ -62,7 +62,7 @@ export default function FavoritesView() { return ( <> - {apiFavorites.length == 0 && ( + {apiFavorites.length === 0 && (
Your favorites are empty. Maybe favorite a server! diff --git a/src/components/docs/Sidebar.tsx b/src/components/docs/Sidebar.tsx index 47f6d7a..02c9398 100644 --- a/src/components/docs/Sidebar.tsx +++ b/src/components/docs/Sidebar.tsx @@ -7,7 +7,7 @@ import { ChevronRight } from "lucide-react"; import { useRouter } from "@/lib/useRouter"; import { AnimatePresence, motion } from "framer-motion"; -export function Sidebar() { +export function sSidebar() { return ( <> {allFolders.map((docs) => ( diff --git a/src/config/version.tsx b/src/config/version.tsx index c515e85..6e0d1ca 100644 --- a/src/config/version.tsx +++ b/src/config/version.tsx @@ -45,324 +45,339 @@ const handleClick = () => { export const Changelog = () => { const router = useRouter(); return ( - <> -
- Running on commit{" "} - - +
+ Running on commit{" "} + + + {( + process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA || "unknown" + ).substring(0, 7)} + {" "} + {process.env.NEXT_PUBLIC_VERCEL_GIT_PULL_REQUEST_ID != undefined && + process.env.NEXT_PUBLIC_VERCEL_GIT_PULL_REQUEST_ID != "" && ( + <> + {" "} + | on PR{" "} + + {process.env.NEXT_PUBLIC_VERCEL_GIT_PULL_REQUEST_ID} + {" "} + by{" "} + + {process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_AUTHOR_NAME} + + + )}{" "} + {process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_MESSAGE != undefined && + `| ${process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_MESSAGE.substring(0, 24)}`} + +
+
+
-
- + - + - -
-
-
- - Version 1.3.0 (September 9th 2024) - -
    -
  • - • Docs:Reading -
  • -
  • - • Achievements are here! See more at{" "} - Docs:Advanced/Achievements -
  • -
  • • Finally fixed Cron actions for the final time™
  • -
  • • Overhauled account preferences
  • -
-
-
-
- - Version 1.2.0 (September 3rd 2024) - -
    -
  • • Added documentation
  • -
  • • Brand new linking of padding and server options
  • -
  • • New system to ensure automatic Cron actions!
  • -
  • • and alot more!
  • -
-
-
-
- - Version 1.1.0 (August 24rd 2024) - -
    -
  • • Brand new hero page
  • -
  • • New padding option on server list
  • -
  • • New help guide
  • -
-
-
-
- - Version 1.0.0 (August 22nd 2024) - -
    -
  • - • 1.0!{" "} - -
  • -
  • • New hover card on server title hover
  • -
  • • Moving to self-hosted cron jobs
  • -
  • • Fixing some mobile issues
  • -
-
-
- + + See more information about MHSF and how to use it + + +
+
+
+ + Version 1.3.2 (October 4th 2024) + + +
+
+
+ + Version 1.3.0 (September 9th 2024) + +
    +
  • + • Docs:Reading +
  • +
  • + • Achievements are here! See more at{" "} + Docs:Advanced/Achievements +
  • +
  • • Finally fixed Cron actions for the final time™
  • +
  • • Overhauled account preferences
  • +
+
+
+
+ + Version 1.2.0 (September 3rd 2024) + +
    +
  • • Added documentation
  • +
  • • Brand new linking of padding and server options
  • +
  • • New system to ensure automatic Cron actions!
  • +
  • • and alot more!
  • +
+
+
+
+ + Version 1.1.0 (August 24rd 2024) + +
    +
  • • Brand new hero page
  • +
  • • New padding option on server list
  • +
  • • New help guide
  • +
+
+
+
+ + Version 1.0.0 (August 22nd 2024) + +
    +
  • + • 1.0!{" "} + +
  • +
  • • New hover card on server title hover
  • +
  • • Moving to self-hosted cron jobs
  • +
  • • Fixing some mobile issues
  • +
+
+
+ -
-
- - Version b-0.10.7 (August 18th 2024) - -
    -
  • • New server information tab on server pages
  • -
-
-
-
- - Version b-0.10.2 (August 18th 2024) - -
    -
  • • Content fades-in on load
  • -
  • • Instead of using spinners, now we are using Skeletons
  • -
-
-
-
- - Version b-0.10.0 (August 17th 2024) - -
    -
  • • Revamped server list button list
  • -
  • • Added welcome dialog when first launching
  • -
  • - • Fixed an issue where servers were still able to be favorited - client-side when logged out -
  • -
  • • Improved MOTD engine
  • -
-
- 👀 - {/** Ensure Tailwind pre-renders all grid column types */} - - - -
-
-
-
- - Version b-0.9.0 (August 15th 2024) - -
    -
  • • Adding favorites sorting option
  • -
  • • Fixed right-click context menu on the server list
  • -
  • • Fixed metadata bugs
  • -
-
- - Hey! Update on statistics. Recently, we have figured out the Minehut - API is blocked to Vercel servers (atleast the /servers{" "} - endpoint). I'm actively trying to find a loop-hole so that statistics - works correctly. Thank you {":)"} - -
-
-
-
- - Version b-0.8.0 (August 11th 2024) - -
    -
  • • Fixing up command bar
  • -
  • • Renaming "Short Term" to "Statistics"
  • -
-
-
-
- - Version b-0.7.2 (August 7th 2024) - -
    -
  • • Adding new spinners to pages that needed it
  • -
  • • Fixed lots of bugs
  • -
  • • Moved from Inngest to Vercel Cron
  • -
-
-
-
- - Version b-0.7.0 (August 7th 2024) - -
    -
  • • Added customization to servers
  • -
  • • New button focus effect
  • -
  • • Lots of bugfixes
  • -
-
-
-
- - Version b-0.6.0 (August 3rd 2024) - -
    -
  • • Enhanced shortcuts
  • -
  • • Added gradient beam to player count
  • -
  • • Updated loading animations
  • -
  • • Lots of bugfixes
  • -
-
-
-
- - Version b-0.4.5 (July 26th 2024): - -
    -
  • • Made charts better
  • -
  • • Sorted API endpoints
  • -
-
-
-
- - Version b-0.4 (July 25th 2024): - -
    -
  • • Added Info button
  • -
  • • Fixed Clerk in production
  • -
  • • Added Turbo for faster builds
  • -
  • - • Added historical data -
  • -
-
-
-
- - Version b-0.3 (July 23th 2024): - -
    -
  • - • Fixed minor bugs described by -
  • -
-
-
-
- - Version b-0.2 (July 23th 2024): - -
    -
  • • Inital release!
  • -
-
-
-
- All developers that helped out: - - cool badge - -
- +
+
+ + Version b-0.10.7 (August 18th 2024) + +
    +
  • • New server information tab on server pages
  • +
+
+
+
+ + Version b-0.10.2 (August 18th 2024) + +
    +
  • • Content fades-in on load
  • +
  • • Instead of using spinners, now we are using Skeletons
  • +
+
+
+
+ + Version b-0.10.0 (August 17th 2024) + +
    +
  • • Revamped server list button list
  • +
  • • Added welcome dialog when first launching
  • +
  • + • Fixed an issue where servers were still able to be favorited + client-side when logged out +
  • +
  • • Improved MOTD engine
  • +
+
+ 👀 + {/** Ensure Tailwind pre-renders all grid column types */} + + + +
+
+
+
+ + Version b-0.9.0 (August 15th 2024) + +
    +
  • • Adding favorites sorting option
  • +
  • • Fixed right-click context menu on the server list
  • +
  • • Fixed metadata bugs
  • +
+
+ + Hey! Update on statistics. Recently, we have figured out the Minehut + API is blocked to Vercel servers (atleast the /servers{" "} + endpoint). I'm actively trying to find a loop-hole so that statistics + works correctly. Thank you {":)"} + +
+
+
+
+ + Version b-0.8.0 (August 11th 2024) + +
    +
  • • Fixing up command bar
  • +
  • • Renaming "Short Term" to "Statistics"
  • +
+
+
+
+ + Version b-0.7.2 (August 7th 2024) + +
    +
  • • Adding new spinners to pages that needed it
  • +
  • • Fixed lots of bugs
  • +
  • • Moved from Inngest to Vercel Cron
  • +
+
+
+
+ + Version b-0.7.0 (August 7th 2024) + +
    +
  • • Added customization to servers
  • +
  • • New button focus effect
  • +
  • • Lots of bugfixes
  • +
+
+
+
+ + Version b-0.6.0 (August 3rd 2024) + +
    +
  • • Enhanced shortcuts
  • +
  • • Added gradient beam to player count
  • +
  • • Updated loading animations
  • +
  • • Lots of bugfixes
  • +
+
+
+
+ + Version b-0.4.5 (July 26th 2024): + +
    +
  • • Made charts better
  • +
  • • Sorted API endpoints
  • +
+
+
+
+ + Version b-0.4 (July 25th 2024): + +
    +
  • • Added Info button
  • +
  • • Fixed Clerk in production
  • +
  • • Added Turbo for faster builds
  • +
  • + • Added historical data +
  • +
+
+
+
+ + Version b-0.3 (July 23th 2024): + +
    +
  • + • Fixed minor bugs described by +
  • +
+
+
+
+ + Version b-0.2 (July 23th 2024): + +
    +
  • • Inital release!
  • +
+
+
+
+ All developers that helped out: + + cool badge + +
+ ); }; const Github = (props: SVGProps) => ( - - + + ); diff --git a/src/lib/linear.ts b/src/lib/linear.ts new file mode 100644 index 0000000..329ecca --- /dev/null +++ b/src/lib/linear.ts @@ -0,0 +1,29 @@ +import { LinearClient, LinearFetch, User } from "@linear/sdk"; + +export async function createReportIssue(server: string, reportDescription: string, userId: string) { + const linearClient = new LinearClient({ + apiKey: process.env.LINEAR + }) + + const allTeams = await linearClient.teams(); + // Always grabs the first issue category. + const team = allTeams.nodes[0]; + + // Ensure there *actually* is a team there + if (team.id) { + await linearClient.createIssue({teamId: team.id, title: `Issue against server \`${server}\``, description: desc(userId, server, reportDescription), assigneeId: (await team.members()).nodes[0].id }) + } +} + +const desc = (user: string, server: string, reason: string) => `There was a report against the server, submitted by a user. +Every issue must be [considered with care](https://list.mlnehut.com/docs/legal/external-content-agreement) before evaluating its outcome. + + +**User**: \`${user}\` +**Server**: \`${server}\` +**For reason**: +${reason} + + +*This was an automatically added issue by the report bot. Add the canceled status to remove the issue from the active issues, along with the labels Not Controllable & Spam for their respective values.* +` \ No newline at end of file diff --git a/src/pages/api/inngest.ts b/src/pages/api/inngest.ts index 4f1f811..07b2310 100644 --- a/src/pages/api/inngest.ts +++ b/src/pages/api/inngest.ts @@ -1,455 +1,95 @@ -import { OnlineServer } from "@/lib/types/mh-server"; +import type { OnlineServer } from "@/lib/types/mh-server"; import { Inngest } from "inngest"; import { serve } from "inngest/next"; import { Document, MongoClient, ObjectId, WithId } from "mongodb"; -import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - Client, - EmbedBuilder, - GatewayIntentBits, - ModalBuilder, - REST, - Routes, - SlashCommandBuilder, - SlashCommandStringOption, - TextChannel, - TextInputBuilder, - TextInputStyle, -} from "discord.js"; +import {createReportIssue} from "@/lib/linear"; -let reporting = true; -let initalizedYet = false; -const commands = [ - new SlashCommandBuilder() - .setName("realive") - .setDescription("Re-alive an existing report that was glitched") - .addStringOption( - new SlashCommandStringOption() - .setName("id") - .setRequired(true) - .setDescription("Report ID") - ), -]; - -let client: Client; - -// this isn't entirely necessary, to run each time the server starts -async function init() { - try { - const rest = new REST({ version: "10" }).setToken( - process.env.DISCORD_TOKEN as string - ); - - try { - console.log("[REPORTING] Started refreshing application (/) commands."); - - await rest.put( - Routes.applicationCommands(process.env.DISCORD_APP_ID as string), - { body: commands } - ); - - console.log( - "[REPORTING] Successfully reloaded application (/) commands." - ); - } catch (error) { - console.error(error); - } - } catch { - console.log( - "[REPORTING] Discord API token not found, skipping reporting..." - ); - reporting = false; - } - client = new Client({ - intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages], - }); - client.on("interactionCreate", async (interaction) => { - if (!interaction.isChatInputCommand()) return; - if (interaction.commandName === "realive") { - await interaction.reply({ - embeds: [ - new EmbedBuilder() - .setTitle("Re-creating report") - .setColor("Blurple") - .setDescription("This may take a few seconds.."), - ], - ephemeral: true, - }); - const mongo = new MongoClient(process.env.MONGO_DB as string); - const db = mongo.db("mhsf"); - const collection = db.collection("reports"); - let reportDoc: WithId | null; - try { - reportDoc = await collection.findOne({ - _id: new ObjectId(interaction.options.getString("id") as string), - }); - } catch { - await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setTitle("Report ID not valid") - .setColor("Red") - .setDescription("This report could not be found."), - ], - }); - return; - } - - if (reportDoc === null) { - await interaction.editReply({ - embeds: [ - new EmbedBuilder() - .setTitle("Report not found") - .setColor("Red") - .setDescription("This report could not be found."), - ], - }); - return; - } - - report({ data: { ...reportDoc, id: reportDoc._id.toString() } }); - } - }); - return; -} // Create a client to send and receive events export const inngest = new Inngest({ id: "mhsf" }); // Create an API that serves zero functions export default serve({ - client: inngest, - functions: [ - inngest.createFunction( - { id: "report" }, - { event: "report-server" }, - async ({ event, step }) => { - if (!reporting) { - throw new Error("Cannot report server: Discord API token not found"); - } + client: inngest, + functions: [ + inngest.createFunction( + { id: "report" }, + { event: "report-server" }, + async ({ event, step }) => { + // by the way, I bombed the Discord stuff + await createReportIssue(event.data.server, event.data.reason, event.data.userId); - if (!initalizedYet) { - await init(); - initalizedYet = true; - await client.login(process.env.DISCORD_TOKEN); + return { event, body: "Done" } + }, + ), + inngest.createFunction( + { id: "short-term-data" }, + [{ cron: "*/30 * * * *" }, { event: "test/30-min" }], + async ({ event, step }) => { + const mongo = new MongoClient(process.env.MONGO_DB as string); + try { + const mh = await step.run("grab-servers-from-api", async () => { + return await ( + await fetch("https://api.minehut.com/servers", { + headers: { + accept: "application/json", + "accept-language": Math.random().toString(), + priority: "u=1, i", + "sec-ch-ua": '"Not/A)Brand";v="8", "Chromium";v="126"', + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": '"macOS"', + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "cross-site", + "Content-Type": "application/json", + Referer: "http://localhost:3000/", + "Referrer-Policy": "strict-origin-when-cross-origin", + }, + body: null, + method: "GET", + }) + ).json(); + }); - console.log(`[REPORTING] Waiting for bot to be ready`); + const mha = mongo.db("mhsf").collection("mh"); + const meta = mongo.db("mhsf").collection("meta"); + const dbl = mongo.db("mhsf").collection("history"); - client.on("ready", () => { - console.log( - `[REPORTING] Bot logged in as ${client.user?.displayName}` - ); - report(event); - }); - return; - } + await mha.insertOne({ + total_players: mh.total_players, + total_servers: mh.total_servers, + date: new Date(), + }); - report(event); - } - ), - inngest.createFunction( - { id: "short-term-data" }, - [{ cron: "*/30 * * * *" }, { event: "test/30-min" }], - async ({ event, step }) => { - const mongo = new MongoClient(process.env.MONGO_DB as string); - try { - const mh = await step.run("grab-servers-from-api", async () => { - return await ( - await fetch("https://api.minehut.com/servers", { - headers: { - accept: "application/json", - "accept-language": Math.random().toString(), - priority: "u=1, i", - "sec-ch-ua": '"Not/A)Brand";v="8", "Chromium";v="126"', - "sec-ch-ua-mobile": "?0", - "sec-ch-ua-platform": '"macOS"', - "sec-fetch-dest": "empty", - "sec-fetch-mode": "cors", - "sec-fetch-site": "cross-site", - "Content-Type": "application/json", - Referer: "http://localhost:3000/", - "Referrer-Policy": "strict-origin-when-cross-origin", - }, - body: null, - method: "GET", - }) - ).json(); - }); + const completed = await step.run("listing-servers", async () => { + mh.servers.forEach(async (server: OnlineServer, i: number) => { + const serverFavoritesObject = await meta.findOne({ + server: server.name, + }); + let favorites = 0; + if (serverFavoritesObject != undefined) + favorites = serverFavoritesObject.favorites; - const mha = mongo.db("mhsf").collection("mh"); - const meta = mongo.db("mhsf").collection("meta"); - const dbl = mongo.db("mhsf").collection("history"); + await dbl.insertOne({ + player_count: server.playerData.playerCount, + favorites, + server: server.name, + date: new Date(), + }); + console.log(i, mh.servers.length); + }); + return true; + }); + if (completed == true) { + return { event, body: "Finished!" }; + } + } catch (e) { + await mongo.close(); - await mha.insertOne({ - total_players: mh.total_players, - total_servers: mh.total_servers, - date: new Date(), - }); - - const completed = await step.run("listing-servers", async () => { - mh.servers.forEach(async (server: OnlineServer, i: number) => { - const serverFavoritesObject = await meta.findOne({ - server: server.name, - }); - let favorites = 0; - if (serverFavoritesObject != undefined) - favorites = serverFavoritesObject.favorites; - - await dbl.insertOne({ - player_count: server.playerData.playerCount, - favorites, - server: server.name, - date: new Date(), - }); - console.log(i, mh.servers.length); - }); - return true; - }); - if (completed == true) { - return { event, body: "Finished!" }; - } - } catch (e) { - await mongo.close(); - - return { event, body: "Cloudflare.. aborting " + e }; - } - } - ), - ], + return { event, body: "Cloudflare.. aborting " + e }; + } + }, + ), + ], }); -async function report(event: any) { - const isTextBased = client.channels.cache.get( - process.env.REPORTS_CHANNEL as string - )?.isTextBased; - if (!isTextBased) { - throw new Error( - "Cannot report server: Report channel not found or not a text channel." - ); - } - const channel = client.channels.cache.get( - process.env.REPORTS_CHANNEL as string - ) as TextChannel; - - const goToServer = new ButtonBuilder() - .setLabel("Go to server") - .setStyle(ButtonStyle.Link) - .setURL("https://list.mlnehut.com/server/" + event.data.server); - - const confirm = new ButtonBuilder() - .setCustomId("resolve") - .setLabel("Resolve") - .setStyle(ButtonStyle.Primary); - const typed = (name: string) => - new ButtonBuilder() - .setCustomId("typed") - .setLabel(name + " is typing") - .setStyle(ButtonStyle.Secondary) - .setDisabled(true); - - const cancel = new ButtonBuilder() - .setCustomId("cancel") - .setLabel("Cancel") - .setStyle(ButtonStyle.Secondary); - - const undo = new ButtonBuilder() - .setCustomId("undo") - .setLabel("Undo") - .setStyle(ButtonStyle.Danger); - - const undor = new ActionRowBuilder().addComponents( - undo, - goToServer - ); - - const rowN = new ActionRowBuilder().addComponents( - confirm, - cancel, - goToServer - ); - - const message = await channel.send({ - embeds: [ - new EmbedBuilder() - .setColor("Orange") - .setTitle("New report to server") - .setTimestamp() - .setDescription( - "A server has been reported by a player. \n Reason: " + - event.data.reason + - (event.data.reason == "" ? "**" : "") - ) - .setFields([ - { name: "User ID", value: `\`${event.data.userId}\`` }, - { name: "Server", value: `${event.data.server}` }, - ]) - .setFooter({ - text: - "Is this report glitched? Use the command /realive id:" + - event.data._id + - " to do actions on this report.", - }), - ], - components: [rowN], - }); - setTimeout(async () => { - await messageLoop(); - - async function messageLoop() { - const confirmation = await message.awaitMessageComponent({}); - if (confirmation.customId == "undo") { - (await confirmation.reply({ content: "Done!" })).delete(); - await message.edit({ - embeds: [ - new EmbedBuilder() - .setColor("Orange") - .setTitle("New report to server") - .setTimestamp() - .setDescription( - "A server has been reported by a player. \n Reason: " + - event.data.reason + - (event.data.reason == "" ? "**" : "") - ) - .setFields([ - { name: "User ID", value: `\`${event.data.userId}\`` }, - { name: "Server", value: `${event.data.server}` }, - ]) - .setFooter({ - text: - "Is this report glitched? Use the command /realive id:" + - event.data._id + - " to do actions on this report.", - }), - ], - components: [rowN], - }); - } - if (confirmation.customId == "resolve") { - await message.edit({ - embeds: [ - new EmbedBuilder() - .setColor("Green") - .setTitle("Server report resolved") - .setTimestamp() - .setDescription( - "The server report has been resolved by <@" + - confirmation.user.id + - "> \n Reason: " + - event.data.reason + - (event.data.reason == "" ? "**" : "") - ) - .setFields([ - { name: "User ID", value: `\`${event.data.userId}\`` }, - { name: "Server", value: `${event.data.server}` }, - ]) - .setFooter({ - text: - "Is this report glitched? Use the command /realive id:" + - event.data._id + - " to do actions on this report.", - }), - ], - components: [undor], - }); - ( - await confirmation.reply({ content: "Done!", ephemeral: true }) - ).delete(); - } - - if (confirmation.customId == "cancel") { - const modal = new ModalBuilder().setCustomId("why").setTitle("MHSF"); - const favoriteColorInput = new TextInputBuilder() - .setCustomId("whyToCancel") - .setLabel("Cancelation reason") - .setStyle(TextInputStyle.Short); - - const row = new ActionRowBuilder().addComponents( - favoriteColorInput - ); - modal.addComponents(row); - confirmation.showModal(modal); - - try { - let reportedYet = false; - await message.edit({ - components: [ - new ActionRowBuilder().addComponents( - typed( - confirmation.user.globalName || confirmation.user.username - ) - ), - ], - }); - setTimeout(async () => { - if (reportedYet == false) { - await message.edit({ - components: [rowN], - }); - - await messageLoop(); - } - - return; - }, 60_000); - const submission = await confirmation.awaitModalSubmit({ - time: 60_000, - }); - const text = submission.fields.getTextInputValue("whyToCancel"); - - if (text == "") { - await submission.reply({ content: "Done!", ephemeral: true }); - await messageLoop(); - } - - reportedYet = true; - - await message.edit({ - embeds: [ - new EmbedBuilder() - .setColor("Red") - .setTitle("Server report cancelled") - .setTimestamp() - .setDescription( - "The server report has been cancelled by <@" + - confirmation.user.id + - "> \n Reason of cancelation: " + - text + - "\nReason of report: " + - event.data.reason + - (event.data.reason == "" ? "**" : "") - ) - .setFields([ - { name: "User ID", value: `\`${event.data.userId}\`` }, - { name: "Server", value: `${event.data.server}` }, - ]) - .setFooter({ - text: - "Is this report glitched? Use the command /realive id:" + - event.data._id + - " to do actions on this report.", - }), - ], - components: [undor], - }); - await submission.reply({ content: "Done!", ephemeral: true }); - } catch (e) { - await message.edit({ - components: [rowN], - }); - await confirmation.reply({ - embeds: [ - new EmbedBuilder() - .setTitle("You took too long!") - .setDescription("Please try again.") - .setColor("Red"), - ], - ephemeral: true, - }); - } - } - await messageLoop(); - } - }, 0); -} diff --git a/src/pages/api/v0/account-sl/change.ts b/src/pages/api/v0/account-sl/change.ts index a3b4242..4aaa9a9 100644 --- a/src/pages/api/v0/account-sl/change.ts +++ b/src/pages/api/v0/account-sl/change.ts @@ -45,3 +45,4 @@ export default async function handler( }); res.status(200).send({ message: "Success" }); } + diff --git a/src/pages/api/v0/achievements/[server].ts b/src/pages/api/v0/achievements/[server].ts index ef599e9..b31b72c 100644 --- a/src/pages/api/v0/achievements/[server].ts +++ b/src/pages/api/v0/achievements/[server].ts @@ -2,17 +2,17 @@ import { MongoClient } from "mongodb"; import { NextApiRequest, NextApiResponse } from "next"; export default async function handler( - req: NextApiRequest, - res: NextApiResponse + req: NextApiRequest, + res: NextApiResponse, ) { - const { server } = req.query; - if (!server) return res.status(400).send({ error: "No server was provided" }); - - const client = new MongoClient(process.env.MONGO_DB as string); - await client.connect(); + const { server } = req.query; + if (!server) return res.status(400).send({ error: "No server was provided" }); - const db = client.db("mhsf"); - const collection = db.collection("achievements"); + const client = new MongoClient(process.env.MONGO_DB as string); + await client.connect(); - res.send({ result: await collection.find({ name: server }).toArray() }); + const db = client.db("mhsf"); + const collection = db.collection("achievements"); + + res.send({ result: await collection.find({ name: server }).toArray() }); } diff --git a/src/pages/api/v1/death-webhook.ts b/src/pages/api/v1/death-webhook.ts index e9e64a5..0971c78 100644 --- a/src/pages/api/v1/death-webhook.ts +++ b/src/pages/api/v1/death-webhook.ts @@ -1,21 +1,21 @@ -import { NextApiRequest, NextApiResponse } from "next"; +import { NextApiRequest, NextApiResponse } from "next"; import { MongoClient } from "mongodb"; export default async function handler( - req: NextApiRequest, - res: NextApiResponse + req: NextApiRequest, + res: NextApiResponse, ) { - if (req.headers.Authentication != process.env.WEBHOOK_AUTH) { - return res.status(401).json({ error: "Unauthorized" }); - } - const { id } = req.body.data; - const client = new MongoClient(process.env.MONGO_DB as string); - await client.connect(); + if (req.headers.Authentication != process.env.WEBHOOK_AUTH) { + return res.status(401).json({ error: "Unauthorized" }); + } + const { id } = req.body.data; + const client = new MongoClient(process.env.MONGO_DB as string); + await client.connect(); - const db = client.db("mhsf"); - const collection = db.collection("claimed-users"); - await collection.findOneAndDelete({ userId: id }); + const db = client.db("mhsf"); + const collection = db.collection("claimed-users"); + await collection.findOneAndDelete({ userId: id }); - res.send({ message: "Done!" }); - client.close(); + res.send({ message: "Done!" }); + client.close(); } diff --git a/yarn.lock b/yarn.lock index b52651b..92e1896 100644 --- a/yarn.lock +++ b/yarn.lock @@ -649,6 +649,11 @@ resolved "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz" integrity sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw== +"@graphql-typed-document-node/core@^3.1.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" + integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== + "@grpc/grpc-js@^1.7.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.11.1.tgz#a92f33e98f1959feffcd1b25a33b113d2c977b70" @@ -753,6 +758,15 @@ jsbi "^4.3.0" tslib "^2.4.1" +"@linear/sdk@^31.0.0": + version "31.0.0" + resolved "https://registry.yarnpkg.com/@linear/sdk/-/sdk-31.0.0.tgz#05faac8bbb9ebd7b530760e9535f5bd7fe2f3618" + integrity sha512-51mKO/R5JBnQERDfg5uMryHGRyavUAkveIiHxxshItvEIwFVACJi8S7N2oabhSlqqNZf2rL0YlVokeRxd72s6A== + dependencies: + "@graphql-typed-document-node/core" "^3.1.0" + graphql "^15.4.0" + isomorphic-unfetch "^3.1.0" + "@mdx-js/esbuild@^2.0.0": version "2.3.0" resolved "https://registry.yarnpkg.com/@mdx-js/esbuild/-/esbuild-2.3.0.tgz#97f2f1b854d904c50bcd0a219b3664657f4fe8c3" @@ -4145,6 +4159,11 @@ graphemer@^1.4.0: resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== +graphql@^15.4.0: + version "15.9.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.9.0.tgz#4e8ca830cfd30b03d44d3edd9cac2b0690304b53" + integrity sha512-GCOQdvm7XxV1S4U4CGrsdlEN37245eC8P9zaYCMr6K1BG0IPGy5lUwmJsEOGyl1GD6HXjOtl2keCP9asRBwNvA== + gray-matter@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-4.0.3.tgz#e893c064825de73ea1f5f7d88c7a9f7274288798" @@ -4735,6 +4754,14 @@ isexe@^2.0.0: resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +isomorphic-unfetch@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz#87341d5f4f7b63843d468438128cb087b7c3e98f" + integrity sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q== + dependencies: + node-fetch "^2.6.1" + unfetch "^4.2.0" + iterator.prototype@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz" @@ -6165,7 +6192,7 @@ node-fetch-native@^1.6.3: resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.4.tgz#679fc8fd8111266d47d7e72c379f1bed9acff06e" integrity sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ== -node-fetch@^2.6.12: +node-fetch@^2.6.1, node-fetch@^2.6.12: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== @@ -7794,6 +7821,11 @@ undici@6.13.0: resolved "https://registry.yarnpkg.com/undici/-/undici-6.13.0.tgz#7edbf4b7f3aac5f8a681d515151bf55cb3589d72" integrity sha512-Q2rtqmZWrbP8nePMq7mOJIN98M0fYvSgV89vwl/BQRT4mDOeY2GXZngfGpcBBhtky3woM7G24wZV3Q304Bv6cw== +unfetch@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be" + integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA== + unified@^10.0.0, unified@^10.1.2: version "10.1.2" resolved "https://registry.yarnpkg.com/unified/-/unified-10.1.2.tgz#b1d64e55dafe1f0b98bb6c719881103ecf6c86df"