This commit is contained in:
nin0 2025-05-29 03:41:47 -04:00
parent 199c2dba16
commit d5eec94b6a
Signed by: nin0
SSH key fingerprint: SHA256:NOoDnFVvZNFvqfXCIhzr6oCTDImZAbTTuyAysZ8Ufk8
9 changed files with 269 additions and 107 deletions

View file

@ -1,7 +1,5 @@
export const Constants = {
APPROVED_CHANNEL_ID: "1371073576903376896",
PENDING_CHANNEL_ID: "1370539719842070683",
REJECTION_CHANNEL_ID: "1371073658403164261",
APPLICATIONS_CHANNEL_ID: "1377060608431751188",
REVIEWER_ROLE_ID: "1375617676139040909",
MOD_ROLE_ID: "1370539692143153152",
MANAGER_ROLE_ID: "1370539689659863091",
@ -15,5 +13,13 @@ export const Constants = {
BAD: 0xffaaaa,
YELLOW: 0xeadb77,
GOOD: 0xaaffaa
},
TAGS: {
PENDING: "1377061012645085194",
INTERVIEWED: "1377061105657970758",
ACCEPTED: "1377061136989425895",
REJECTED: "1377061177099681833",
WITHDRAWN: "1377222222254702642",
BANNED: "1377061220825436170"
}
};

View file

@ -17,13 +17,11 @@ export function PendingApplicationMessage(props: {
user: OUser;
response: Response;
locked?: boolean;
threadID: string;
}) {
const { id, user, response } = props;
const locked = props.locked || false;
return (
<ComponentMessage>
<TextDisplay>{"<@&1375617676139040909>"}</TextDisplay>
<Container
accentColor={
!locked ? Constants.COLORS.NEW_REQ : Constants.COLORS.YELLOW
@ -91,7 +89,7 @@ export function PendingApplicationMessage(props: {
</ActionRow>
<ActionRow>
<StringSelect
customID="deny-reasons"
customID={`reject-${id}-predefined`}
placeholder="Deny reasons"
disabled={locked}
// @ts-expect-error
@ -110,7 +108,6 @@ export function PendingApplicationMessage(props: {
})}
/>
</ActionRow>
<TextDisplay>-# Discuss in {`<#${props.threadID}>`}</TextDisplay>
</ComponentMessage>
);
}

View file

@ -12,7 +12,7 @@ export function User(props: { user: DiscordUser }) {
<TextDisplay>
{user.globalName || user.username}
<br />
-# @{user.username}
-# @{user.username} ({user.id})
</TextDisplay>
</Section>
);

View file

@ -16,7 +16,7 @@ client.on("interactionCreate", async (interaction) => {
if (interaction.type === InteractionTypes.MESSAGE_COMPONENT)
if (interaction.data.componentType === ComponentTypes.BUTTON) {
if (interaction.data.customID.split("-")[0] === "accept") {
await interaction.defer(MessageFlags.EPHEMERAL);
await interaction.defer();
if (
!canUser(interaction.member!, "review") ||
(!canUser(interaction.member!, "owner") &&
@ -33,12 +33,10 @@ client.on("interactionCreate", async (interaction) => {
);
await db.run(
"DELETE FROM applications WHERE id=?",
application.id
);
await client.rest.channels.deleteMessage(
application.channel_id,
application.message_id
`UPDATE applications SET status=1 WHERE id=?`,
interaction.data.customID.split("-")[
interaction.data.customID.split("-").length - 1
]
);
await selfappReq(
@ -50,14 +48,14 @@ client.on("interactionCreate", async (interaction) => {
);
const user = await client.rest.users.get(application.user_id);
await interaction.createFollowup({
flags: MessageFlags.EPHEMERAL,
content: `<:blobcatgreen:1375806000312881233> Approved @${user.tag}'s join request!`
content: `<:blobcatgreen:1375806000312881233> **Approved** \`@${user.tag}\`'s join request!`
});
const response: Response = JSON.parse(application.responses);
const msg = await client.rest.channels.createMessage(
Constants.APPROVED_CHANNEL_ID,
const msg = await client.rest.channels.editMessage(
application.channel_id,
application.message_id,
<ComponentMessage>
<Container accentColor={Constants.COLORS.GOOD}>
<TextDisplay>## Join request accepted</TextDisplay>
@ -91,25 +89,11 @@ client.on("interactionCreate", async (interaction) => {
})()
});
await client.rest.request({
auth: `Bot ${process.env.BOT_TOKEN}`,
method: "POST",
path: `/channels/${application.thread_id}/messages`,
json: {
content: "",
flags: 0,
message_reference: {
channel_id: msg.channelID,
guild_id: msg.guildID!,
message_id: msg.id,
type: 1
}
}
});
await client.rest.channels.edit(application.thread_id, {
archived: true,
locked: true,
reason: `${user.tag}'s application has been accepted`
reason: `${user.tag}'s application has been accepted`,
appliedTags: [Constants.TAGS.ACCEPTED]
});
}
}

View file

@ -2,6 +2,7 @@ import { ComponentTypes, InteractionTypes, MessageFlags } from "oceanic.js";
import { client } from "..";
import { canUser } from "../utils/utils";
import { selfappReq } from "../utils/selfappReq";
import { Constants } from "~/Constants";
client.on("interactionCreate", async (interaction) => {
if (interaction.type === InteractionTypes.MESSAGE_COMPONENT)
@ -28,6 +29,12 @@ client.on("interactionCreate", async (interaction) => {
)) as any
).code;
client.rest.channels.edit(interaction.channelID, {
appliedTags: [
Constants.TAGS.PENDING,
Constants.TAGS.INTERVIEWED
]
});
return await interaction.createFollowup({
flags: MessageFlags.EPHEMERAL,
content: `https://discord.gg/${gdmInvite}`

View file

@ -19,7 +19,6 @@ client.on("interactionCreate", async (interaction) => {
"SELECT * FROM applications WHERE message_id=?",
interaction.message.id
);
console.log(application);
switch (interaction.data.customID.split("-")[0]) {
case "lock": {
@ -31,7 +30,6 @@ client.on("interactionCreate", async (interaction) => {
application.user_id
)}
locked={true}
threadID={application.thread_id}
/>
);
break;
@ -45,7 +43,6 @@ client.on("interactionCreate", async (interaction) => {
application.user_id
)}
locked={false}
threadID={application.thread_id}
/>
);
break;

View file

@ -0,0 +1,152 @@
import {
AnyComponentSelectMenuInteraction,
ComponentInteraction,
ComponentTypes,
InteractionTypes,
MessageFlags,
ModalSubmitInteraction,
TextInputStyles
} from "oceanic.js";
import { client } from "..";
import { canUser } from "../utils/utils";
import { selfappReq } from "../utils/selfappReq";
import { Response } from "~/utils/types";
import { db } from "~/utils/database";
import { ComponentMessage } from "components-jsx/ComponentMessage";
import { Container } from "components-jsx/Container";
import { Divider } from "components-jsx/Divider";
import { TextDisplay } from "components-jsx/TextDisplay";
import { ApplicationContent } from "~/components/ApplicationContent";
import { User } from "~/components/User";
import { Constants } from "~/Constants";
import { TextInput } from "components-jsx/TextInput";
import { ActionRow } from "components-jsx/ActionRow";
import { rejectReasons } from "~/utils/rejectReasons";
export async function rejectUser(
interaction: ComponentInteraction | ModalSubmitInteraction,
reason: string = ""
) {
await interaction.defer();
const shouldBan = interaction.data.customID.includes("ban");
const application = await db.get(
"SELECT * FROM applications WHERE id=?",
interaction.data.customID.split("-")[
interaction.data.customID.split("-").length - 2
]
);
const user = await client.rest.users.get(application.user_id);
await interaction.createFollowup({
content: `${
shouldBan
? "<:BAN:1375806319621046313>"
: "<:blobcatred:1375806202470203513>"
} **Rejected** \`@${user.tag}\`'s join request${
shouldBan ? " and banned them" : ""
}!`
});
const response: Response = JSON.parse(application.responses);
const msg = await client.rest.channels.editMessage(
application.channel_id,
application.message_id,
<ComponentMessage>
<Container accentColor={Constants.COLORS.BAD}>
<TextDisplay>## Join request rejected</TextDisplay>
<Divider />
<User user={user} />
<Divider />
<ApplicationContent response={response} includeDetails={true} />
<Divider />
<TextDisplay>
### Reason
<br />
{reason}
</TextDisplay>
</Container>
</ComponentMessage>
);
await db.run(
`UPDATE applications SET status=-1, reject_reason=?, actioned_by=?, message_id=? WHERE id=?`,
reason,
interaction.member!.id,
msg.id,
interaction.data.customID.split("-")[
interaction.data.customID.split("-").length - 1
]
);
await selfappReq(
`/guilds/${interaction.guildID}/requests/id/${application.id}`,
"PATCH",
{
action: "REJECTED",
rejection_reason: reason
}
);
shouldBan &&
(await interaction.guild?.createBan(user.id, {
reason
}));
await client.rest.channels.edit(application.thread_id, {
locked: true,
reason: `${user.tag}'s application has been rejected`,
appliedTags: [Constants.TAGS.REJECTED]
});
}
client.on("interactionCreate", async (interaction) => {
if (interaction.type === InteractionTypes.MODAL_SUBMIT) {
await rejectUser(
interaction,
`${interaction.member?.tag}: ${
interaction.data.components.getTextInput("reason") ||
"No reason provided"
}`
);
}
if (interaction.type === InteractionTypes.MESSAGE_COMPONENT) {
if (interaction.data.componentType === ComponentTypes.BUTTON) {
if (interaction.data.customID.split("-")[0] === "reject") {
if (!canUser(interaction.member!, "review"))
return await interaction.createFollowup({
flags: MessageFlags.EPHEMERAL,
content: "💢 nop"
});
await interaction.createModal({
title: `Reject ${
interaction.data.customID.includes("ban")
? "and ban "
: ""
}user`,
components: [
<ActionRow>
<TextInput
customID="reason"
label="Reason"
style={TextInputStyles.PARAGRAPH}
maxLength={126}
required={false}
/>
</ActionRow>
],
customID: interaction.data.customID
});
}
}
if (interaction.data.componentType === ComponentTypes.STRING_SELECT) {
await rejectUser(
interaction,
`${interaction.member!.tag}: ${
rejectReasons[interaction.data.values.getStrings()[0]]
.reason
}`
);
}
}
});

View file

@ -28,6 +28,7 @@ import { ApplicationContent } from "./components/ApplicationContent";
import("./joinRequestActions/lockUnlock");
import("./joinRequestActions/interview");
import("./joinRequestActions/accept");
import("./joinRequestActions/reject");
export async function setupJoinRequestHandler(shard: Shard) {
shard.ws?.on("message", async (d) => {
@ -61,19 +62,9 @@ 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,
{
const baller = {
name: `${user.tag}'s application`,
type: ChannelTypes.PUBLIC_THREAD,
autoArchiveDuration: 10080
}
);
const pendingMsg =
await client.rest.channels.createMessage(
Constants.PENDING_CHANNEL_ID,
message: (
<PendingApplicationMessage
id={applicationData.request.id}
response={response}
@ -81,8 +72,15 @@ export async function setupJoinRequestHandler(shard: Shard) {
locked={
response.foundThrough === "sold"
}
threadID={thread.id}
/>
),
appliedTags: [Constants.TAGS.PENDING]
};
console.log(JSON.stringify(baller));
const thread =
await client.rest.channels.startThreadInThreadOnlyChannel(
Constants.APPLICATIONS_CHANNEL_ID,
baller
);
const fullApplicantProfile: any = await selfappReq(
@ -94,6 +92,7 @@ export async function setupJoinRequestHandler(shard: Shard) {
);
thread.createMessage({
content: `<@&${Constants.REVIEWER_ROLE_ID}> new application from \`@${user.tag}\``,
embeds: [
{
color: Constants.COLORS.NEW_REQ,
@ -111,8 +110,8 @@ export async function setupJoinRequestHandler(shard: Shard) {
"INSERT INTO applications (id, user_id, status, message_id, channel_id, responses, thread_id) VALUES (?, ?, 0, ?, ?, ?, ?)",
applicationData.request.id,
applicationData.request.user_id,
pendingMsg.id,
pendingMsg.channelID,
thread.id,
thread.id,
JSON.stringify(response),
thread.id
);
@ -131,23 +130,19 @@ export async function setupJoinRequestHandler(shard: Shard) {
applicationData.user_id
);
const response: Response = JSON.parse(
application ? application.responses : "{}" // this will never be used if no applications
);
if (application) {
await db.run(
"DELETE FROM applications WHERE id=?",
applicationData.id
);
await client.rest.channels.deleteMessage(
application.channel_id,
application.message_id
);
}
const response: Response = JSON.parse(
application ? application.responses : {} // this will never be used if no applications
);
const msg = await client.rest.channels.createMessage(
Constants.REJECTION_CHANNEL_ID,
if (application.status === 1) return;
client.rest.channels.editMessage(
application.thread_id,
application.message_id,
<ComponentMessage>
<Container accentColor={Constants.COLORS.BAD}>
<TextDisplay>
@ -156,44 +151,68 @@ export async function setupJoinRequestHandler(shard: Shard) {
<Divider />
<User user={user} />
<Divider />
{application ? (
<ApplicationContent
response={response}
includeDetails={true}
/>
) : (
{application.reject_reason && <Divider />}
{application.reject_reason && (
<TextDisplay>
### Application
### Rejection reason
<br />
User hasn't applied
{application.reject_reason}
</TextDisplay>
)}
</Container>
</ComponentMessage>
);
await client.rest.request({
auth: `Bot ${process.env.BOT_TOKEN}`,
method: "POST",
path: `/channels/${application.thread_id}/messages`,
json: {
content: "",
flags: 0,
message_reference: {
channel_id: msg.channelID,
guild_id: msg.guildID!,
message_id: msg.id,
type: 1
}
}
});
if (application)
await client.rest.channels.edit(application.thread_id, {
archived: true,
locked: true,
reason: `${user.tag}'s application has been withdrawn`
reason: `${user.tag}'s application has been withdrawn`,
appliedTags: [Constants.TAGS.WITHDRAWN]
});
application.reject_reason &&
client.rest.channels.edit(application.thread_id, {
appliedTags: [
Constants.TAGS.REJECTED,
Constants.TAGS.WITHDRAWN
]
});
} else {
const th =
await client.rest.channels.startThreadInThreadOnlyChannel(
Constants.APPLICATIONS_CHANNEL_ID,
{
name: `${user.tag}'s application`,
message: (
<ComponentMessage>
<Container
accentColor={
Constants.COLORS.BAD
}
>
<TextDisplay>
## Join request withdrawn
</TextDisplay>
<Divider />
<User user={user} />
<Divider />
<TextDisplay>
### Application
<br />
User hasn't applied
</TextDisplay>
</Container>
</ComponentMessage>
),
appliedTags: [Constants.TAGS.WITHDRAWN]
}
);
th.edit({
locked: true
});
}
break;
}
}

View file

@ -18,6 +18,6 @@ export const rejectReasons: {
},
ai: {
shortDesc: "AI",
reason: "You have obviously used AI in your application. Therefore, you will not be allowed to reapply."
reason: "You have obviously used AI in your application."
}
};