diff --git a/components-jsx/ComponentMessage.tsx b/components-jsx/ComponentMessage.tsx
index f9a7dd0..f722ba1 100644
--- a/components-jsx/ComponentMessage.tsx
+++ b/components-jsx/ComponentMessage.tsx
@@ -1,14 +1,26 @@
-import { CreateMessageOptions, EditMessageOptions, MessageComponent, MessageFlags } from "oceanic.js";
+import {
+ CreateMessageOptions,
+ EditMessageOptions,
+ InteractionOptions,
+ MessageComponent,
+ MessageFlags
+} from "oceanic.js";
import { childrenToArray } from "./utils";
type MessageOptions = CreateMessageOptions | EditMessageOptions;
-export type ComponentMessageProps = MessageOptions & { children: MessageComponent[]; };
+export type ComponentMessageProps = MessageOptions & {
+ children: MessageComponent[];
+};
-export function ComponentMessage({ children, flags, ...props }: ComponentMessageProps): MessageOptions {
- return {
- flags: MessageFlags.IS_COMPONENTS_V2 | (flags ?? 0),
- components: childrenToArray(children),
- ...props
- };
+export function ComponentMessage({
+ children,
+ flags,
+ ...props
+}: ComponentMessageProps): MessageOptions {
+ return {
+ flags: MessageFlags.IS_COMPONENTS_V2 | (flags ?? 0),
+ components: childrenToArray(children),
+ ...props
+ };
}
diff --git a/src/Constants.ts b/src/Constants.ts
index b0d4873..1a07fff 100644
--- a/src/Constants.ts
+++ b/src/Constants.ts
@@ -1,6 +1,10 @@
export const Constants = {
PENDING_CHANNEL_ID: "1370539719842070683",
REJECTION_CHANNEL_ID: "1371073658403164261",
+ REVIEWER_ROLE_ID: "1375617676139040909",
+ MOD_ROLE_ID: "1370539692143153152",
+ MANAGER_ROLE_ID: "1370539689659863091",
+ OWNER_ID: "886685857560539176",
COLORS: {
NEW_REQ: 0xaaaaff,
BAD: 0xffaaaa,
diff --git a/src/components/ApplicationContent.tsx b/src/components/ApplicationContent.tsx
index 97a14c8..1ae1ac3 100644
--- a/src/components/ApplicationContent.tsx
+++ b/src/components/ApplicationContent.tsx
@@ -1,5 +1,5 @@
import { TextDisplay } from "components-jsx/TextDisplay";
-import { Response } from "~/types";
+import { Response } from "~/utils/types";
export function ApplicationContent(props: {
response: Response;
diff --git a/src/components/PendingApplicationMessage.tsx b/src/components/PendingApplicationMessage.tsx
index e5f6565..80ebe71 100644
--- a/src/components/PendingApplicationMessage.tsx
+++ b/src/components/PendingApplicationMessage.tsx
@@ -5,16 +5,19 @@ import { Container } from "components-jsx/Container";
import { Divider } from "components-jsx/Divider";
import { TextDisplay } from "components-jsx/TextDisplay";
import { ButtonStyles, User as OUser } from "oceanic.js";
-import { Response } from "~/types";
+import { Response } from "~/utils/types";
import { User } from "./User";
import { Constants } from "~/Constants";
import { ApplicationContent } from "./ApplicationContent";
+import { StringSelect } from "components-jsx/StringSelect";
+import { rejectReasons } from "~/utils/rejectReasons";
export function PendingApplicationMessage(props: {
id: string;
user: OUser;
response: Response;
locked?: boolean;
+ threadID: string;
}) {
const { id, user, response } = props;
const locked = props.locked || false;
@@ -30,83 +33,84 @@ export function PendingApplicationMessage(props: {
-
-
-
- ### Details
-
- {response.details}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ return {
+ label: rejectReasons[key].shortDesc,
+ description:
+ rejectReasons[key].reason.length > 100
+ ? `${rejectReasons[key].reason.slice(
+ 0,
+ 97
+ )}...`
+ : rejectReasons[key].reason,
+ value: key
+ };
+ })}
+ />
+
+ -# Discuss in {`<#${props.threadID}>`}
);
}
diff --git a/src/index.ts b/src/index.ts
index d2ebf50..b7d185a 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,8 +1,8 @@
import { AllIntents, Client, ComponentTypes, MessageFlags } from "oceanic.js";
-import { selfappReq } from "./selfappReq";
+import { selfappReq } from "./utils/selfappReq";
import { setupJoinRequestHandler } from "./joinRequestHandler";
import { Constants } from "./Constants";
-import { openDb } from "./database";
+import { openDb } from "./utils/database";
export const client = new Client({
auth: `Bot ${process.env.BOT_TOKEN}`,
@@ -22,6 +22,12 @@ client.on("ready", async () => {
setupJoinRequestHandler(client.shards.first()!);
});
+client.on("messageCreate", (msg) => {
+ if (msg.messageReference && msg.author.id === client.user.id) {
+ if (!msg.messageReference.messageID) msg.delete();
+ }
+});
+
process.on("uncaughtException", (e) => {
console.error(e);
});
diff --git a/src/joinRequestActions/interview.ts b/src/joinRequestActions/interview.ts
new file mode 100644
index 0000000..034f2c0
--- /dev/null
+++ b/src/joinRequestActions/interview.ts
@@ -0,0 +1,37 @@
+import { ComponentTypes, InteractionTypes, MessageFlags } from "oceanic.js";
+import { client } from "..";
+import { canUser } from "../utils/utils";
+import { selfappReq } from "../utils/selfappReq";
+
+client.on("interactionCreate", async (interaction) => {
+ if (interaction.type === InteractionTypes.MESSAGE_COMPONENT)
+ if (interaction.data.componentType === ComponentTypes.BUTTON) {
+ if (interaction.data.customID.split("-")[0] === "interview") {
+ await interaction.defer(MessageFlags.EPHEMERAL);
+ if (!canUser(interaction.member!, "review"))
+ return await interaction.createFollowup({
+ flags: MessageFlags.EPHEMERAL,
+ content: "💢 nop"
+ });
+ const gdmID = (
+ (await selfappReq(
+ `/join-requests/${
+ interaction.data.customID.split("-")[1]
+ }/interview`,
+ "POST"
+ )) as any
+ ).id;
+ const gdmInvite = (
+ (await selfappReq(
+ `/channels/${gdmID}/invites`,
+ "POST"
+ )) as any
+ ).code;
+
+ return await interaction.createFollowup({
+ flags: MessageFlags.EPHEMERAL,
+ content: `https://discord.gg/${gdmInvite}`
+ });
+ }
+ }
+});
diff --git a/src/joinRequestActions/lockUnlock.tsx b/src/joinRequestActions/lockUnlock.tsx
new file mode 100644
index 0000000..9b87ea1
--- /dev/null
+++ b/src/joinRequestActions/lockUnlock.tsx
@@ -0,0 +1,55 @@
+import { ComponentTypes, InteractionTypes, MessageFlags } from "oceanic.js";
+import { client } from "..";
+import { db } from "../utils/database";
+import { PendingApplicationMessage } from "../components/PendingApplicationMessage";
+import { canUser } from "../utils/utils";
+
+client.on("interactionCreate", async (interaction) => {
+ if (interaction.type === InteractionTypes.MESSAGE_COMPONENT)
+ if (interaction.data.componentType === ComponentTypes.BUTTON) {
+ if (!interaction.data.customID.includes("lock")) return;
+
+ if (!canUser(interaction.member!, "owner"))
+ return await interaction.createMessage({
+ flags: MessageFlags.EPHEMERAL,
+ content: "💢 nop"
+ });
+
+ const application = await db.get(
+ "SELECT * FROM applications WHERE message_id=?",
+ interaction.message.id
+ );
+ console.log(application);
+
+ switch (interaction.data.customID.split("-")[0]) {
+ case "lock": {
+ await interaction.editParent(
+
+ );
+ break;
+ }
+ case "unlock": {
+ await interaction.editParent(
+
+ );
+ break;
+ }
+ }
+ }
+});
diff --git a/src/joinRequestHandler.tsx b/src/joinRequestHandler.tsx
index 597d88d..0c0fcbb 100644
--- a/src/joinRequestHandler.tsx
+++ b/src/joinRequestHandler.tsx
@@ -1,7 +1,13 @@
-import { ButtonStyles, ComponentTypes, MessageFlags, Shard } from "oceanic.js";
+import {
+ ButtonStyles,
+ ChannelTypes,
+ ComponentTypes,
+ MessageFlags,
+ Shard
+} from "oceanic.js";
import { client } from ".";
import { Constants } from "./Constants";
-import { db } from "./database";
+import { db } from "./utils/database";
import {
ActionRow,
Button,
@@ -12,13 +18,16 @@ import {
Separator,
TextDisplay
} from "~/components";
-import { selfappReq } from "./selfappReq";
+import { selfappReq } from "./utils/selfappReq";
import { User } from "./components/User";
-import { Response } from "./types";
-import { match } from "./utils";
+import { Response } from "./utils/types";
+import { match } from "./utils/utils";
import { PendingApplicationMessage } from "./components/PendingApplicationMessage";
import { ApplicationContent } from "./components/ApplicationContent";
+import("./joinRequestActions/lockUnlock");
+import("./joinRequestActions/interview");
+
export async function setupJoinRequestHandler(shard: Shard) {
shard.ws?.on("message", async (d) => {
const data = JSON.parse(d.toString("utf8"));
@@ -51,6 +60,16 @@ export async function setupJoinRequestHandler(shard: Shard) {
const user = await client.rest.users.get(
applicationData.request.user.id
);
+ const thread =
+ await client.rest.channels.startThreadWithoutMessage(
+ Constants.PENDING_CHANNEL_ID,
+ {
+ name: `${user.tag}'s application`,
+ type: ChannelTypes.PUBLIC_THREAD,
+ autoArchiveDuration: 10080
+ }
+ );
+
const pendingMsg =
await client.rest.channels.createMessage(
Constants.PENDING_CHANNEL_ID,
@@ -61,14 +80,10 @@ export async function setupJoinRequestHandler(shard: Shard) {
locked={
response.foundThrough === "sold"
}
+ threadID={thread.id}
/>
);
- const thread = await pendingMsg.startThread({
- name: `${user.tag}'s application`,
- autoArchiveDuration: 10080
- });
-
const fullApplicantProfile: any = await selfappReq(
`/users/${user.id}/profile`,
"GET",
@@ -127,7 +142,7 @@ export async function setupJoinRequestHandler(shard: Shard) {
}
const response: Response = JSON.parse(
- application.responses
+ application ? application.responses : {} // this will never be used if no applications
);
const msg = await client.rest.channels.createMessage(
diff --git a/src/utils.ts b/src/utils.ts
deleted file mode 100644
index 5b95965..0000000
--- a/src/utils.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-export function match(
- value: any,
- matches: {
- [key: number | string]: any;
- }
-) {
- if (matches[value]) return matches[value];
- else return null;
-}
diff --git a/src/database.ts b/src/utils/database.ts
similarity index 100%
rename from src/database.ts
rename to src/utils/database.ts
diff --git a/src/utils/rejectReasons.ts b/src/utils/rejectReasons.ts
new file mode 100644
index 0000000..08b4041
--- /dev/null
+++ b/src/utils/rejectReasons.ts
@@ -0,0 +1,23 @@
+export const rejectReasons: {
+ [key: string]: {
+ shortDesc: string;
+ reason: string;
+ };
+} = {
+ low_quality: {
+ shortDesc: "Too low quality",
+ reason: "Your application is blatantly low effort (eg. not a language in languages or a single word application). Feel free to reapply, but actually read the questions"
+ },
+ no_english: {
+ shortDesc: "No English",
+ reason: "You must be fluent in English to join"
+ },
+ elaborate: {
+ shortDesc: "Didn't say enough about themselves",
+ reason: "Write a bit more about yourself and it's very likely that you'll be accepted!"
+ },
+ ai: {
+ shortDesc: "AI",
+ reason: "You have obviously used AI in your application. Therefore, you will not be allowed to reapply."
+ }
+};
diff --git a/src/selfappReq.ts b/src/utils/selfappReq.ts
similarity index 96%
rename from src/selfappReq.ts
rename to src/utils/selfappReq.ts
index a2d5e11..cbde29f 100644
--- a/src/selfappReq.ts
+++ b/src/utils/selfappReq.ts
@@ -12,8 +12,6 @@ export async function selfappReq(
return `?${new URLSearchParams(data).toString()}`;
})();
- console.log(url);
-
return await fetch(url, {
method,
headers: {
diff --git a/src/types.ts b/src/utils/types.ts
similarity index 100%
rename from src/types.ts
rename to src/utils/types.ts
diff --git a/src/utils/utils.ts b/src/utils/utils.ts
new file mode 100644
index 0000000..e470baa
--- /dev/null
+++ b/src/utils/utils.ts
@@ -0,0 +1,48 @@
+import { Member } from "oceanic.js";
+import { Constants } from "../Constants";
+
+export function match(
+ value: any,
+ matches: {
+ [key: number | string]: any;
+ }
+) {
+ if (matches[value]) return matches[value];
+ else return null;
+}
+
+export function canUser(
+ member: Member,
+ can: "review" | "moderate" | "manage" | "owner"
+) {
+ switch (can) {
+ case "review":
+ return (
+ member.roles.some((role) =>
+ [
+ Constants.REVIEWER_ROLE_ID,
+ Constants.MOD_ROLE_ID,
+ Constants.MANAGER_ROLE_ID
+ ].includes(role)
+ ) || member.id === Constants.OWNER_ID
+ );
+ case "moderate":
+ return (
+ member.roles.some((role) =>
+ [Constants.MOD_ROLE_ID, Constants.MANAGER_ROLE_ID].includes(
+ role
+ )
+ ) || member.id === Constants.OWNER_ID
+ );
+ case "manage":
+ return (
+ member.roles.some((role) =>
+ [Constants.MANAGER_ROLE_ID].includes(role)
+ ) || member.id === Constants.OWNER_ID
+ );
+ case "owner":
+ return member.id === Constants.OWNER_ID;
+ default:
+ return false;
+ }
+}