threading & locked applications
This commit is contained in:
parent
9191b156d7
commit
97d607871c
5 changed files with 259 additions and 137 deletions
|
@ -1,4 +1,10 @@
|
|||
export const Constants = {
|
||||
PENDING_CHANNEL_ID: "1370539719842070683",
|
||||
REJECTION_CHANNEL_ID: "1371073658403164261"
|
||||
REJECTION_CHANNEL_ID: "1371073658403164261",
|
||||
COLORS: {
|
||||
NEW_REQ: 0xaaaaff,
|
||||
BAD: 0xffaaaa,
|
||||
YELLOW: 0xeadb77,
|
||||
GOOD: 0xaaffaa
|
||||
}
|
||||
};
|
||||
|
|
47
src/components/ApplicationContent.tsx
Normal file
47
src/components/ApplicationContent.tsx
Normal file
|
@ -0,0 +1,47 @@
|
|||
import { TextDisplay } from "components-jsx/TextDisplay";
|
||||
import { Response } from "~/types";
|
||||
|
||||
export function ApplicationContent(props: {
|
||||
response: Response;
|
||||
includeDetails?: boolean;
|
||||
}) {
|
||||
const { response } = props;
|
||||
return (
|
||||
<TextDisplay>
|
||||
### Application
|
||||
<br />
|
||||
Here for
|
||||
<br />
|
||||
-# {response.hereFor.join(", ")}
|
||||
<br />
|
||||
Found through
|
||||
<br />
|
||||
-#{" "}
|
||||
{(() => {
|
||||
switch (response.foundThrough) {
|
||||
case "archive":
|
||||
return "Guild Archive/nelly.tools";
|
||||
case "tag":
|
||||
return 'Hit "Ask to Join" on a clan tag';
|
||||
case "user":
|
||||
return "User invited them\n-# **Only accept if someone is mentioned in details**";
|
||||
case "other":
|
||||
return "Something else";
|
||||
case "sold":
|
||||
return "Was sold an invite\n-# **Only the owner can interact with this application**";
|
||||
}
|
||||
})()}
|
||||
<br />
|
||||
Languages
|
||||
<br />
|
||||
-# {response.languages}
|
||||
<br />
|
||||
Can boost
|
||||
<br />
|
||||
-# {response.canBoost ? "Yes" : "No"}
|
||||
{props.includeDetails
|
||||
? `\nDetails\n-# ${response.details.replaceAll("\n", "\n-# ")}`
|
||||
: ""}
|
||||
</TextDisplay>
|
||||
);
|
||||
}
|
112
src/components/PendingApplicationMessage.tsx
Normal file
112
src/components/PendingApplicationMessage.tsx
Normal file
|
@ -0,0 +1,112 @@
|
|||
import { ActionRow } from "components-jsx/ActionRow";
|
||||
import { Button } from "components-jsx/Button";
|
||||
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 { ButtonStyles, User as OUser } from "oceanic.js";
|
||||
import { Response } from "~/types";
|
||||
import { User } from "./User";
|
||||
import { Constants } from "~/Constants";
|
||||
import { ApplicationContent } from "./ApplicationContent";
|
||||
|
||||
export function PendingApplicationMessage(props: {
|
||||
id: string;
|
||||
user: OUser;
|
||||
response: Response;
|
||||
locked?: boolean;
|
||||
}) {
|
||||
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
|
||||
}
|
||||
>
|
||||
<TextDisplay>## New join request</TextDisplay>
|
||||
<Divider />
|
||||
<User user={user} />
|
||||
<Divider />
|
||||
<ApplicationContent response={response} />
|
||||
<Divider />
|
||||
<TextDisplay>
|
||||
### Details
|
||||
<br />
|
||||
{response.details}
|
||||
</TextDisplay>
|
||||
<Divider />
|
||||
<ActionRow>
|
||||
<Button
|
||||
style={ButtonStyles.SUCCESS}
|
||||
customID={`accept-${id}`}
|
||||
emoji={{
|
||||
name: "blobcatgreen",
|
||||
id: "1375806000312881233"
|
||||
}}
|
||||
disabled={locked}
|
||||
>
|
||||
Accept
|
||||
</Button>
|
||||
<Button
|
||||
style={ButtonStyles.SUCCESS}
|
||||
customID={`accept-friend-${id}`}
|
||||
emoji={{
|
||||
name: "blobcatgreen",
|
||||
id: "1375806000312881233"
|
||||
}}
|
||||
disabled={locked}
|
||||
>
|
||||
Accept + Friend
|
||||
</Button>
|
||||
</ActionRow>
|
||||
<ActionRow>
|
||||
<Button
|
||||
style={ButtonStyles.DANGER}
|
||||
customID={`reject-${id}`}
|
||||
emoji={{
|
||||
name: "blobcatred",
|
||||
id: "1375806202470203513"
|
||||
}}
|
||||
disabled={locked}
|
||||
>
|
||||
Deny
|
||||
</Button>
|
||||
<Button
|
||||
style={ButtonStyles.DANGER}
|
||||
customID={`reject-ban-${id}`}
|
||||
emoji={{
|
||||
name: "BAN",
|
||||
id: "1375806319621046313"
|
||||
}}
|
||||
disabled={locked}
|
||||
>
|
||||
Deny + Ban
|
||||
</Button>
|
||||
</ActionRow>
|
||||
<ActionRow>
|
||||
<Button
|
||||
style={ButtonStyles.SECONDARY}
|
||||
customID={`interview-${id}`}
|
||||
emoji={{
|
||||
name: "💬"
|
||||
}}
|
||||
>
|
||||
Interview
|
||||
</Button>
|
||||
<Button
|
||||
style={ButtonStyles.SECONDARY}
|
||||
customID={`${locked ? "un" : ""}lock-${id}`}
|
||||
emoji={{
|
||||
name: "🔑"
|
||||
}}
|
||||
>
|
||||
{!locked ? "Lock" : "Unlock"}
|
||||
</Button>
|
||||
</ActionRow>
|
||||
</Container>
|
||||
</ComponentMessage>
|
||||
);
|
||||
}
|
|
@ -16,6 +16,8 @@ import { selfappReq } from "./selfappReq";
|
|||
import { User } from "./components/User";
|
||||
import { Response } from "./types";
|
||||
import { match } from "./utils";
|
||||
import { PendingApplicationMessage } from "./components/PendingApplicationMessage";
|
||||
import { ApplicationContent } from "./components/ApplicationContent";
|
||||
|
||||
export async function setupJoinRequestHandler(shard: Shard) {
|
||||
shard.ws?.on("message", async (d) => {
|
||||
|
@ -52,140 +54,51 @@ export async function setupJoinRequestHandler(shard: Shard) {
|
|||
const pendingMsg =
|
||||
await client.rest.channels.createMessage(
|
||||
Constants.PENDING_CHANNEL_ID,
|
||||
<ComponentMessage>
|
||||
<TextDisplay>
|
||||
{"<@&1375617676139040909>"}
|
||||
</TextDisplay>
|
||||
<Container accentColor={0xaaaaff}>
|
||||
<TextDisplay>
|
||||
## New join request
|
||||
</TextDisplay>
|
||||
<Divider />
|
||||
<User user={user} />
|
||||
<Divider />
|
||||
<TextDisplay>
|
||||
### Application
|
||||
<br />
|
||||
Here for
|
||||
<br />
|
||||
-# {response.hereFor.join(", ")}
|
||||
<br />
|
||||
Found through
|
||||
<br />
|
||||
-#{" "}
|
||||
{(() => {
|
||||
switch (
|
||||
response.foundThrough
|
||||
) {
|
||||
case "archive":
|
||||
return "Guild Archive/nelly.tools";
|
||||
case "tag":
|
||||
return 'Hit "Ask to Join" on a clan tag';
|
||||
case "user":
|
||||
return "User invited them\n-# **Only accept if someone is mentioned in details**";
|
||||
case "other":
|
||||
return "Something else";
|
||||
case "sold":
|
||||
return "Was sold an invite\n-# **Only the owner can interact with this application**";
|
||||
<PendingApplicationMessage
|
||||
id={applicationData.request.id}
|
||||
response={response}
|
||||
user={user}
|
||||
locked={
|
||||
response.foundThrough === "sold"
|
||||
}
|
||||
})()}
|
||||
<br />
|
||||
Languages
|
||||
<br />
|
||||
-# {response.languages}
|
||||
<br />
|
||||
Can boost
|
||||
<br />
|
||||
-#{" "}
|
||||
{response.canBoost
|
||||
? "Yes"
|
||||
: "No"}
|
||||
</TextDisplay>
|
||||
<Divider />
|
||||
<TextDisplay>
|
||||
### Details
|
||||
<br />
|
||||
{response.details}
|
||||
</TextDisplay>
|
||||
<Divider />
|
||||
<ActionRow>
|
||||
<Button
|
||||
style={ButtonStyles.SUCCESS}
|
||||
customID={`accept-${applicationData.request.id}`}
|
||||
emoji={{
|
||||
name: "blobcatgreen",
|
||||
id: "1375806000312881233"
|
||||
}}
|
||||
>
|
||||
Accept
|
||||
</Button>
|
||||
<Button
|
||||
style={ButtonStyles.SUCCESS}
|
||||
customID={`accept-friend-${applicationData.request.id}`}
|
||||
emoji={{
|
||||
name: "blobcatgreen",
|
||||
id: "1375806000312881233"
|
||||
}}
|
||||
>
|
||||
Accept + Friend
|
||||
</Button>
|
||||
</ActionRow>
|
||||
<ActionRow>
|
||||
<Button
|
||||
style={ButtonStyles.DANGER}
|
||||
customID={`reject-${applicationData.request.id}`}
|
||||
emoji={{
|
||||
name: "blobcatred",
|
||||
id: "1375806202470203513"
|
||||
}}
|
||||
>
|
||||
Deny
|
||||
</Button>
|
||||
<Button
|
||||
style={ButtonStyles.DANGER}
|
||||
customID={`reject-ban-${applicationData.request.id}`}
|
||||
emoji={{
|
||||
name: "BAN",
|
||||
id: "1375806319621046313"
|
||||
}}
|
||||
>
|
||||
Deny + Ban
|
||||
</Button>
|
||||
</ActionRow>
|
||||
<ActionRow>
|
||||
<Button
|
||||
style={
|
||||
ButtonStyles.SECONDARY
|
||||
}
|
||||
customID={`interview-${applicationData.request.id}`}
|
||||
emoji={{
|
||||
name: "💬"
|
||||
}}
|
||||
>
|
||||
Interview
|
||||
</Button>
|
||||
<Button
|
||||
style={
|
||||
ButtonStyles.SECONDARY
|
||||
}
|
||||
customID={`lock-${applicationData.request.id}`}
|
||||
emoji={{
|
||||
name: "🔑"
|
||||
}}
|
||||
>
|
||||
Lock
|
||||
</Button>
|
||||
</ActionRow>
|
||||
</Container>
|
||||
</ComponentMessage>
|
||||
/>
|
||||
);
|
||||
|
||||
const thread = await pendingMsg.startThread({
|
||||
name: `${user.tag}'s application`,
|
||||
autoArchiveDuration: 10080
|
||||
});
|
||||
|
||||
const fullApplicantProfile: any = await selfappReq(
|
||||
`/users/${user.id}/profile`,
|
||||
"GET",
|
||||
{
|
||||
join_request_id: applicationData.request.id
|
||||
}
|
||||
);
|
||||
|
||||
thread.createMessage({
|
||||
embeds: [
|
||||
{
|
||||
color: Constants.COLORS.NEW_REQ,
|
||||
title: "User bio",
|
||||
description:
|
||||
"```\n" +
|
||||
fullApplicantProfile.user_profile
|
||||
.bio +
|
||||
"\n```"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
await db.run(
|
||||
"INSERT INTO applications (id, user_id, status, message_id, channel_id, responses) VALUES (?, ?, 0, ?, ?, ?)",
|
||||
"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,
|
||||
JSON.stringify(response)
|
||||
JSON.stringify(response),
|
||||
thread.id
|
||||
);
|
||||
|
||||
break;
|
||||
|
@ -198,6 +111,10 @@ export async function setupJoinRequestHandler(shard: Shard) {
|
|||
"SELECT * FROM applications WHERE id=?",
|
||||
applicationData.id
|
||||
);
|
||||
const user = await client.rest.users.get(
|
||||
applicationData.user_id
|
||||
);
|
||||
|
||||
if (application) {
|
||||
await db.run(
|
||||
"DELETE FROM applications WHERE id=?",
|
||||
|
@ -208,30 +125,59 @@ export async function setupJoinRequestHandler(shard: Shard) {
|
|||
application.message_id
|
||||
);
|
||||
}
|
||||
const user = await client.rest.users.get(
|
||||
applicationData.user_id
|
||||
|
||||
const response: Response = JSON.parse(
|
||||
application.responses
|
||||
);
|
||||
await client.rest.channels.createMessage(
|
||||
|
||||
const msg = await client.rest.channels.createMessage(
|
||||
Constants.REJECTION_CHANNEL_ID,
|
||||
<ComponentMessage>
|
||||
<Container accentColor={0xffaaaa}>
|
||||
<Container accentColor={Constants.COLORS.BAD}>
|
||||
<TextDisplay>
|
||||
## Join request withdrawn
|
||||
</TextDisplay>
|
||||
<Divider />
|
||||
<User user={user} />
|
||||
<Divider />
|
||||
<TextDisplay>### Application</TextDisplay>
|
||||
|
||||
{application ? (
|
||||
<TextDisplay>User has applied</TextDisplay>
|
||||
<ApplicationContent
|
||||
response={response}
|
||||
includeDetails={true}
|
||||
/>
|
||||
) : (
|
||||
<TextDisplay>
|
||||
### Application
|
||||
<br />
|
||||
User hasn't applied
|
||||
</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, {
|
||||
locked: true,
|
||||
reason: `${user.tag}'s application has been withdrawn`
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,23 @@ export async function selfappReq(
|
|||
method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE",
|
||||
data?: object
|
||||
) {
|
||||
return await fetch("https://discord.com/api/v9" + path, {
|
||||
const url =
|
||||
"https://discord.com/api/v9" +
|
||||
path +
|
||||
(() => {
|
||||
if (!data || method !== "GET") return "";
|
||||
// @ts-expect-error
|
||||
return `?${new URLSearchParams(data).toString()}`;
|
||||
})();
|
||||
|
||||
console.log(url);
|
||||
|
||||
return await fetch(url, {
|
||||
method,
|
||||
headers: {
|
||||
Authorization: process.env.USER_TOKEN!,
|
||||
...(data ? { "Content-Type": "application/json" } : {})
|
||||
},
|
||||
body: data ? JSON.stringify(data || {}) : null
|
||||
body: data && method !== "GET" ? JSON.stringify(data || {}) : null
|
||||
}).then((e) => e.json());
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue