Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Prevent entry requests from being accepted or rejected while an inquiry is ongoing. #364

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion assets/localisations/entry/eng-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@
"entry.verification.vote.sureToForce.reject.description": "Are you sure you want to forcibly reject this entry request?",
"entry.verification.vote.sureToForce.yes": "Yes, I am sure",
"entry.verification.vote.sureToForce.no": "No, cancel",
"entry.verification.vote.inquiryInProgress.title": "Cannot vote during inquiry",
"entry.verification.vote.inquiryInProgress.description": "Voting on this entry request is currently disabled because an inquiry is in progress.",
"entry.verification.inquiry.inquiry": "Inquiry",
"entry.verification.inquiry.open": "Open Inquiry",
"entry.verification.inquiry.channel": "Inquiry channel for {user}.",
Expand All @@ -68,4 +70,4 @@
"entry.verification.inquiry.opened.title": "Inquiry opened!",
"entry.verification.inquiry.opened.description": "An inquiry has been opened to review the user's request to join {guild_name}.",
"entry.verification.inquiry.verificationAnswers": "Verification Answers"
}
}
4 changes: 4 additions & 0 deletions source/constants/contexts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1567,6 +1567,10 @@ export default Object.freeze({
cannotUseUntil: localise("interactions.rateLimited.description.cannotUseAgainUntil", locale),
},
}),
inquiryInProgress: ({ localise, locale }) => ({
title: localise("entry.verification.vote.inquiryInProgress.title", locale)(),
description: localise("entry.verification.vote.inquiryInProgress.description", locale)(),
}),
noReports: ({ localise, locale }) => ({
title: localise("allUpToDate", locale)(),
description: localise("reports.noReports", locale)(),
Expand Down
37 changes: 22 additions & 15 deletions source/library/services/prompts/tickets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { Model } from "logos/models/model.ts";
import { Ticket, type TicketFormData, type TicketType } from "logos/models/ticket";
import { User } from "logos/models/user";
import { PromptService } from "logos/services/prompts/service";
import type { EntryRequest } from "logos/models/entry-request.ts";
import { Model } from "logos/models/model.ts";

class TicketPromptService extends PromptService<{
type: "tickets";
Expand Down Expand Up @@ -38,12 +40,6 @@ class TicketPromptService extends PromptService<{
}

getPromptContent(user: Logos.User, ticketDocument: Ticket): Discord.CreateMessageOptions | undefined {
// Inquiry tickets are hidden, and are not meant to be interactable.
// For all intents and purposes, verification prompts are kind of like their controller.
if (ticketDocument.type === "inquiry") {
return undefined;
}

const strings = constants.contexts.promptControls({
localise: this.client.localise,
locale: this.guildLocale,
Expand Down Expand Up @@ -165,6 +161,26 @@ class TicketPromptService extends PromptService<{
await this.client.bot.helpers.deleteChannel(ticketDocument.channelId).catch(() => {
this.log.warn("Failed to delete ticket channel.");
});

if (ticketDocument.type === "inquiry") {
await this.#handleCloseInquiry(ticketDocument);
}
}

async #handleCloseInquiry(ticketDocument: Ticket): Promise<void> {
const entryRequestDocument = this.client.documents.entryRequests.get(
Model.buildPartialId<EntryRequest>({
guildId: ticketDocument.guildId,
authorId: ticketDocument.authorId,
}),
);
if (entryRequestDocument === undefined || entryRequestDocument.ticketChannelId === undefined) {
return;
}

await entryRequestDocument.update(this.client, () => {
entryRequestDocument.ticketChannelId = undefined;
});
}

async openTicket({
Expand Down Expand Up @@ -308,20 +324,11 @@ class TicketPromptService extends PromptService<{
}
}

ticketService.registerDocument(ticketDocument);
ticketService.registerHandler(ticketDocument);

if (type === "inquiry") {
return ticketDocument;
}

const prompt = await ticketService.savePrompt(user, ticketDocument);
if (prompt === undefined) {
return undefined;
}

ticketService.registerPrompt(prompt, user.id, ticketDocument);

return ticketDocument;
}
}
Expand Down
46 changes: 20 additions & 26 deletions source/library/services/prompts/verification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { InteractionCollector } from "logos/collectors";
import type { EntryRequest, VoteType } from "logos/models/entry-request";
import type { Guild } from "logos/models/guild";
import { Model } from "logos/models/model";
import { Ticket } from "logos/models/ticket";
import { User } from "logos/models/user";
import { PromptService } from "logos/services/prompts/service";

Expand Down Expand Up @@ -274,13 +273,6 @@ class VerificationPromptService extends PromptService<{
return undefined;
}

const newVote: VoteType = interaction.metadata[2] === "true" ? "for" : "against";

const voter = interaction.member;
if (voter === undefined) {
return undefined;
}

const entryRequestDocument = this.client.documents.entryRequests.get(
Model.buildPartialId<EntryRequest>({ guildId, authorId }),
);
Expand All @@ -289,6 +281,26 @@ class VerificationPromptService extends PromptService<{
return undefined;
}

if (entryRequestDocument.ticketChannelId !== undefined) {
const strings = constants.contexts.inquiryInProgress({
localise: this.client.localise.bind(this.client),
locale: interaction.locale,
});
await this.client.warning(interaction, {
title: strings.title,
description: strings.description,
color: constants.colours.warning,
});
return;
}

const newVote: VoteType = interaction.metadata[2] === "true" ? "for" : "against";

const voter = interaction.member;
if (voter === undefined) {
return undefined;
}

const currentVote = entryRequestDocument.getUserVote({ userId: interaction.user.id.toString() });

const management = this.configuration.management;
Expand Down Expand Up @@ -602,24 +614,6 @@ class VerificationPromptService extends PromptService<{
await this.client.tryLog("entryRequestReject", { guildId: guild.id, args: [author, voter] });
}

if (entryRequestDocument.ticketChannelId !== undefined) {
const ticketService = this.client.getPromptService(this.guildId, { type: "tickets" });
if (ticketService !== undefined) {
const [ticketDocument] = await Ticket.getAll(this.client, {
where: { guildId: this.guildIdString, channelId: entryRequestDocument.ticketChannelId },
});
if (ticketDocument === undefined) {
throw new Error("Unable to find ticket document.");
}

await ticketService.handleDelete(ticketDocument);

await entryRequestDocument.update(this.client, () => {
entryRequestDocument.ticketChannelId = undefined;
});
}
}

return true;
}

Expand Down