mirror of
https://github.com/DeveloLongScript/MHSF.git
synced 2026-05-07 14:54:58 -05:00
release: 1.3.2
This commit is contained in:
parent
07ec6cb89b
commit
6aff5751c6
@ -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=<the token you saw>
|
||||
CLERK_SECRET_KEY=<the token you saw>
|
||||
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 `<server url>/api/inngest`
|
||||
|
||||
@ -4,6 +4,10 @@
|
||||
"rules": {
|
||||
"style": {
|
||||
"useTemplate": "off"
|
||||
},
|
||||
"suspicious": {
|
||||
"noExplicitAny": "off",
|
||||
"noDoubleEquals": "warn"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -12,7 +12,6 @@ const nextConfig = {
|
||||
},
|
||||
async redirects() {
|
||||
return [
|
||||
// Basic redirect
|
||||
{
|
||||
source: '/docs',
|
||||
destination: '/docs/getting-started',
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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 <div className={`theme-${color}`}>{children}</div>;
|
||||
|
||||
@ -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 && (
|
||||
<div className="flex items-center justify-center">
|
||||
<XIcon />
|
||||
Your favorites are empty. Maybe favorite a server!
|
||||
|
||||
@ -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) => (
|
||||
|
||||
@ -86,11 +86,11 @@ export const Changelog = () => {
|
||||
}
|
||||
>
|
||||
<span className="group-hover:underline flex items-center">
|
||||
<Discord className="mr-2" /> Discord
|
||||
<Discord className="mr-2"/> Discord
|
||||
</span>
|
||||
<Marquee
|
||||
className="hidden group-hover:flex font-normal"
|
||||
style={{ "--duration": "15s" }}
|
||||
style={{"--duration": "15s"}}
|
||||
>
|
||||
Join the offical Minehut Discord server! Talk to people that like
|
||||
MHSF too!
|
||||
@ -103,11 +103,11 @@ export const Changelog = () => {
|
||||
}
|
||||
>
|
||||
<span className="group-hover:underline flex items-center">
|
||||
<Github className="mr-2" fill={useDepTheme()} /> Star on GitHub
|
||||
<Github className="mr-2" fill={useDepTheme()}/> Star on GitHub
|
||||
</span>
|
||||
<Marquee
|
||||
className="hidden group-hover:flex font-normal"
|
||||
style={{ "--duration": "10s" }}
|
||||
style={{"--duration": "10s"}}
|
||||
>
|
||||
Support the development of MHSF by starring it on GitHub!
|
||||
</Marquee>
|
||||
@ -117,17 +117,31 @@ export const Changelog = () => {
|
||||
onClick={() => window.open("/docs", "_blank")}
|
||||
>
|
||||
<span className="group-hover:underline flex items-center">
|
||||
<BookIcon className="mr-2" size={16} /> See the docs
|
||||
<BookIcon className="mr-2" size={16}/> See the docs
|
||||
</span>
|
||||
<Marquee
|
||||
className="hidden group-hover:flex font-normal"
|
||||
style={{ "--duration": "10s" }}
|
||||
style={{"--duration": "10s"}}
|
||||
>
|
||||
See more information about MHSF and how to use it
|
||||
</Marquee>
|
||||
</Button>
|
||||
</div>
|
||||
<br />
|
||||
<br/>
|
||||
<div>
|
||||
<strong className="flex items-center">
|
||||
Version 1.3.2 (October 4th 2024)
|
||||
</strong>
|
||||
<ul>
|
||||
<li>
|
||||
• Minor backend changes
|
||||
</li>
|
||||
<li>
|
||||
• <A alt="Please check on GitHub for statuses about this project.">Special:GitHub/releases/tag/1.3.2</A>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<br/>
|
||||
<div>
|
||||
<strong className="flex items-center">
|
||||
Version 1.3.0 (September 9th 2024)
|
||||
@ -144,7 +158,7 @@ export const Changelog = () => {
|
||||
<li>• Overhauled account preferences</li>
|
||||
</ul>
|
||||
</div>
|
||||
<br />
|
||||
<br/>
|
||||
<div>
|
||||
<strong className="flex items-center">
|
||||
Version 1.2.0 (September 3rd 2024)
|
||||
@ -156,7 +170,7 @@ export const Changelog = () => {
|
||||
<li>• and alot more!</li>
|
||||
</ul>
|
||||
</div>
|
||||
<br />
|
||||
<br/>
|
||||
<div>
|
||||
<strong className="flex items-center">
|
||||
Version 1.1.0 (August 24rd 2024)
|
||||
@ -167,7 +181,7 @@ export const Changelog = () => {
|
||||
<li>• New help guide</li>
|
||||
</ul>
|
||||
</div>
|
||||
<br />
|
||||
<br/>
|
||||
<div>
|
||||
<strong className="flex items-center">
|
||||
Version 1.0.0 (August 22nd 2024)
|
||||
@ -184,10 +198,10 @@ export const Changelog = () => {
|
||||
<li>• Fixing some mobile issues</li>
|
||||
</ul>
|
||||
</div>
|
||||
<br />
|
||||
<Separator />
|
||||
<br/>
|
||||
<Separator/>
|
||||
|
||||
<br />
|
||||
<br/>
|
||||
<div>
|
||||
<strong className="flex items-center">
|
||||
Version b-0.10.7 (August 18th 2024)
|
||||
@ -196,7 +210,7 @@ export const Changelog = () => {
|
||||
<li>• New server information tab on server pages</li>
|
||||
</ul>
|
||||
</div>
|
||||
<br />
|
||||
<br/>
|
||||
<div>
|
||||
<strong className="flex items-center">
|
||||
Version b-0.10.2 (August 18th 2024)
|
||||
@ -206,7 +220,7 @@ export const Changelog = () => {
|
||||
<li>• Instead of using spinners, now we are using Skeletons</li>
|
||||
</ul>
|
||||
</div>
|
||||
<br />
|
||||
<br/>
|
||||
<div>
|
||||
<strong className="flex items-center">
|
||||
Version b-0.10.0 (August 17th 2024)
|
||||
@ -220,15 +234,15 @@ export const Changelog = () => {
|
||||
</li>
|
||||
<li>• Improved MOTD engine</li>
|
||||
</ul>
|
||||
<br />
|
||||
<br/>
|
||||
<i>👀</i>
|
||||
{/** Ensure Tailwind pre-renders all grid column types */}
|
||||
<span className="grid-cols-6" />
|
||||
<span className="grid-cols-5" />
|
||||
<span className="grid-cols-4" />
|
||||
<span className="grid-cols-6"/>
|
||||
<span className="grid-cols-5"/>
|
||||
<span className="grid-cols-4"/>
|
||||
</div>
|
||||
<br />
|
||||
<br />
|
||||
<br/>
|
||||
<br/>
|
||||
<div>
|
||||
<strong className="flex items-center">
|
||||
Version b-0.9.0 (August 15th 2024)
|
||||
@ -238,16 +252,16 @@ export const Changelog = () => {
|
||||
<li>• Fixed right-click context menu on the server list</li>
|
||||
<li>• Fixed metadata bugs</li>
|
||||
</ul>
|
||||
<br />
|
||||
<br/>
|
||||
<i>
|
||||
Hey! Update on statistics. Recently, we have figured out the Minehut
|
||||
API is blocked to Vercel servers (atleast the <code>/servers</code>{" "}
|
||||
endpoint). I'm actively trying to find a loop-hole so that statistics
|
||||
works correctly. Thank you {":)"}
|
||||
</i>
|
||||
<br />
|
||||
<br/>
|
||||
</div>
|
||||
<br />
|
||||
<br/>
|
||||
<div>
|
||||
<strong className="flex items-center">
|
||||
Version b-0.8.0 (August 11th 2024)
|
||||
@ -257,7 +271,7 @@ export const Changelog = () => {
|
||||
<li>• Renaming "Short Term" to "Statistics"</li>
|
||||
</ul>
|
||||
</div>
|
||||
<br />
|
||||
<br/>
|
||||
<div>
|
||||
<strong className="flex items-center">
|
||||
Version b-0.7.2 (August 7th 2024)
|
||||
@ -268,7 +282,7 @@ export const Changelog = () => {
|
||||
<li>• Moved from Inngest to Vercel Cron</li>
|
||||
</ul>
|
||||
</div>
|
||||
<br />
|
||||
<br/>
|
||||
<div>
|
||||
<strong className="flex items-center">
|
||||
Version b-0.7.0 (August 7th 2024)
|
||||
@ -279,7 +293,7 @@ export const Changelog = () => {
|
||||
<li>• Lots of bugfixes</li>
|
||||
</ul>
|
||||
</div>
|
||||
<br />
|
||||
<br/>
|
||||
<div>
|
||||
<strong className="flex items-center">
|
||||
Version b-0.6.0 (August 3rd 2024)
|
||||
@ -291,7 +305,7 @@ export const Changelog = () => {
|
||||
<li>• Lots of bugfixes</li>
|
||||
</ul>
|
||||
</div>
|
||||
<br />
|
||||
<br/>
|
||||
<div>
|
||||
<strong className="flex items-center">
|
||||
Version b-0.4.5 (July 26th 2024):
|
||||
@ -301,7 +315,7 @@ export const Changelog = () => {
|
||||
<li>• Sorted API endpoints</li>
|
||||
</ul>
|
||||
</div>
|
||||
<br />
|
||||
<br/>
|
||||
<div>
|
||||
<strong className="flex items-center">
|
||||
Version b-0.4 (July 25th 2024):
|
||||
@ -315,18 +329,18 @@ export const Changelog = () => {
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<br />
|
||||
<br/>
|
||||
<div>
|
||||
<strong className="flex items-center">
|
||||
Version b-0.3 (July 23th 2024):
|
||||
</strong>
|
||||
<ul>
|
||||
<li>
|
||||
• Fixed minor bugs described by <User user="@Tarna" />
|
||||
• Fixed minor bugs described by <User user="@Tarna"/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<br />
|
||||
<br/>
|
||||
<div>
|
||||
<strong className="flex items-center">
|
||||
Version b-0.2 (July 23th 2024):
|
||||
@ -335,7 +349,7 @@ export const Changelog = () => {
|
||||
<li>• Inital release!</li>
|
||||
</ul>
|
||||
</div>
|
||||
<br />
|
||||
<br/>
|
||||
<div>
|
||||
<strong>All developers that helped out:</strong>
|
||||
<Link href="https://dvelo.vercel.app">
|
||||
@ -362,7 +376,8 @@ const Github = (props: SVGProps<SVGSVGElement>) => (
|
||||
preserveAspectRatio="xMidYMid"
|
||||
{...props}
|
||||
>
|
||||
<path d="M128.001 0C57.317 0 0 57.307 0 128.001c0 56.554 36.676 104.535 87.535 121.46 6.397 1.185 8.746-2.777 8.746-6.158 0-3.052-.12-13.135-.174-23.83-35.61 7.742-43.124-15.103-43.124-15.103-5.823-14.795-14.213-18.73-14.213-18.73-11.613-7.944.876-7.78.876-7.78 12.853.902 19.621 13.19 19.621 13.19 11.417 19.568 29.945 13.911 37.249 10.64 1.149-8.272 4.466-13.92 8.127-17.116-28.431-3.236-58.318-14.212-58.318-63.258 0-13.975 5-25.394 13.188-34.358-1.329-3.224-5.71-16.242 1.24-33.874 0 0 10.749-3.44 35.21 13.121 10.21-2.836 21.16-4.258 32.038-4.307 10.878.049 21.837 1.47 32.066 4.307 24.431-16.56 35.165-13.12 35.165-13.12 6.967 17.63 2.584 30.65 1.255 33.873 8.207 8.964 13.173 20.383 13.173 34.358 0 49.163-29.944 59.988-58.447 63.157 4.591 3.972 8.682 11.762 8.682 23.704 0 17.126-.148 30.91-.148 35.126 0 3.407 2.304 7.398 8.792 6.14C219.37 232.5 256 184.537 256 128.002 256 57.307 198.691 0 128.001 0Zm-80.06 182.34c-.282.636-1.283.827-2.194.39-.929-.417-1.45-1.284-1.15-1.922.276-.655 1.279-.838 2.205-.399.93.418 1.46 1.293 1.139 1.931Zm6.296 5.618c-.61.566-1.804.303-2.614-.591-.837-.892-.994-2.086-.375-2.66.63-.566 1.787-.301 2.626.591.838.903 1 2.088.363 2.66Zm4.32 7.188c-.785.545-2.067.034-2.86-1.104-.784-1.138-.784-2.503.017-3.05.795-.547 2.058-.055 2.861 1.075.782 1.157.782 2.522-.019 3.08Zm7.304 8.325c-.701.774-2.196.566-3.29-.49-1.119-1.032-1.43-2.496-.726-3.27.71-.776 2.213-.558 3.315.49 1.11 1.03 1.45 2.505.701 3.27Zm9.442 2.81c-.31 1.003-1.75 1.459-3.199 1.033-1.448-.439-2.395-1.613-2.103-2.626.301-1.01 1.747-1.484 3.207-1.028 1.446.436 2.396 1.602 2.095 2.622Zm10.744 1.193c.036 1.055-1.193 1.93-2.715 1.95-1.53.034-2.769-.82-2.786-1.86 0-1.065 1.202-1.932 2.733-1.958 1.522-.03 2.768.818 2.768 1.868Zm10.555-.405c.182 1.03-.875 2.088-2.387 2.37-1.485.271-2.861-.365-3.05-1.386-.184-1.056.893-2.114 2.376-2.387 1.514-.263 2.868.356 3.061 1.403Z" />
|
||||
<path
|
||||
d="M128.001 0C57.317 0 0 57.307 0 128.001c0 56.554 36.676 104.535 87.535 121.46 6.397 1.185 8.746-2.777 8.746-6.158 0-3.052-.12-13.135-.174-23.83-35.61 7.742-43.124-15.103-43.124-15.103-5.823-14.795-14.213-18.73-14.213-18.73-11.613-7.944.876-7.78.876-7.78 12.853.902 19.621 13.19 19.621 13.19 11.417 19.568 29.945 13.911 37.249 10.64 1.149-8.272 4.466-13.92 8.127-17.116-28.431-3.236-58.318-14.212-58.318-63.258 0-13.975 5-25.394 13.188-34.358-1.329-3.224-5.71-16.242 1.24-33.874 0 0 10.749-3.44 35.21 13.121 10.21-2.836 21.16-4.258 32.038-4.307 10.878.049 21.837 1.47 32.066 4.307 24.431-16.56 35.165-13.12 35.165-13.12 6.967 17.63 2.584 30.65 1.255 33.873 8.207 8.964 13.173 20.383 13.173 34.358 0 49.163-29.944 59.988-58.447 63.157 4.591 3.972 8.682 11.762 8.682 23.704 0 17.126-.148 30.91-.148 35.126 0 3.407 2.304 7.398 8.792 6.14C219.37 232.5 256 184.537 256 128.002 256 57.307 198.691 0 128.001 0Zm-80.06 182.34c-.282.636-1.283.827-2.194.39-.929-.417-1.45-1.284-1.15-1.922.276-.655 1.279-.838 2.205-.399.93.418 1.46 1.293 1.139 1.931Zm6.296 5.618c-.61.566-1.804.303-2.614-.591-.837-.892-.994-2.086-.375-2.66.63-.566 1.787-.301 2.626.591.838.903 1 2.088.363 2.66Zm4.32 7.188c-.785.545-2.067.034-2.86-1.104-.784-1.138-.784-2.503.017-3.05.795-.547 2.058-.055 2.861 1.075.782 1.157.782 2.522-.019 3.08Zm7.304 8.325c-.701.774-2.196.566-3.29-.49-1.119-1.032-1.43-2.496-.726-3.27.71-.776 2.213-.558 3.315.49 1.11 1.03 1.45 2.505.701 3.27Zm9.442 2.81c-.31 1.003-1.75 1.459-3.199 1.033-1.448-.439-2.395-1.613-2.103-2.626.301-1.01 1.747-1.484 3.207-1.028 1.446.436 2.396 1.602 2.095 2.622Zm10.744 1.193c.036 1.055-1.193 1.93-2.715 1.95-1.53.034-2.769-.82-2.786-1.86 0-1.065 1.202-1.932 2.733-1.958 1.522-.03 2.768.818 2.768 1.868Zm10.555-.405c.182 1.03-.875 2.088-2.387 2.37-1.485.271-2.861-.365-3.05-1.386-.184-1.056.893-2.114 2.376-2.387 1.514-.263 2.868.356 3.061 1.403Z" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
|
||||
29
src/lib/linear.ts
Normal file
29
src/lib/linear.ts
Normal file
@ -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.*
|
||||
`
|
||||
@ -1,119 +1,9 @@
|
||||
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<Document> | 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" });
|
||||
|
||||
@ -125,28 +15,11 @@ export default serve({
|
||||
{ id: "report" },
|
||||
{ event: "report-server" },
|
||||
async ({ event, step }) => {
|
||||
if (!reporting) {
|
||||
throw new Error("Cannot report server: Discord API token not found");
|
||||
}
|
||||
// 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);
|
||||
|
||||
console.log(`[REPORTING] Waiting for bot to be ready`);
|
||||
|
||||
client.on("ready", () => {
|
||||
console.log(
|
||||
`[REPORTING] Bot logged in as ${client.user?.displayName}`
|
||||
);
|
||||
report(event);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
report(event);
|
||||
}
|
||||
return { event, body: "Done" }
|
||||
},
|
||||
),
|
||||
inngest.createFunction(
|
||||
{ id: "short-term-data" },
|
||||
@ -214,242 +87,9 @@ export default serve({
|
||||
|
||||
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<ButtonBuilder>().addComponents(
|
||||
undo,
|
||||
goToServer
|
||||
);
|
||||
|
||||
const rowN = new ActionRowBuilder<ButtonBuilder>().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 == "" ? "*<empty>*" : "")
|
||||
)
|
||||
.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 == "" ? "*<empty>*" : "")
|
||||
)
|
||||
.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 == "" ? "*<empty>*" : "")
|
||||
)
|
||||
.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<TextInputBuilder>().addComponents(
|
||||
favoriteColorInput
|
||||
);
|
||||
modal.addComponents(row);
|
||||
confirmation.showModal(modal);
|
||||
|
||||
try {
|
||||
let reportedYet = false;
|
||||
await message.edit({
|
||||
components: [
|
||||
new ActionRowBuilder<ButtonBuilder>().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 == "" ? "*<empty>*" : "")
|
||||
)
|
||||
.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);
|
||||
}
|
||||
|
||||
@ -45,3 +45,4 @@ export default async function handler(
|
||||
});
|
||||
res.status(200).send({ message: "Success" });
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ import { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
res: NextApiResponse,
|
||||
) {
|
||||
const { server } = req.query;
|
||||
if (!server) return res.status(400).send({ error: "No server was provided" });
|
||||
|
||||
@ -3,7 +3,7 @@ import { MongoClient } from "mongodb";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
res: NextApiResponse,
|
||||
) {
|
||||
if (req.headers.Authentication != process.env.WEBHOOK_AUTH) {
|
||||
return res.status(401).json({ error: "Unauthorized" });
|
||||
|
||||
34
yarn.lock
34
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"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user