3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-05-25 10:25:01 +00:00
This commit is contained in:
Almeida 2023-03-10 13:24:39 -06:00 committed by GitHub
commit fa3b20cb60
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 52 additions and 60 deletions

View file

@ -43,7 +43,6 @@ export const CasesModCmd = modActionsCmd({
const prefix = getGuildPrefix(pluginData);
createPaginatedMessage(
pluginData.client,
msg.channel,
totalPages,
async (page) => {

View file

@ -1,4 +1,5 @@
import {
Formatters,
GuildMember,
Message,
MessageActionRow,
@ -35,6 +36,15 @@ export enum SearchType {
BanSearch,
}
interface SearchResult<T> {
results: T[];
totalResults: number;
page: number;
lastPage: number;
from: number;
to: number;
}
class SearchError extends Error {}
type MemberSearchParams = ArgsFromSignatureOrArray<typeof searchCmdSignature>;
@ -90,7 +100,7 @@ export async function displaySearch(
const perPage = args.ids ? SEARCH_ID_RESULTS_PER_PAGE : SEARCH_RESULTS_PER_PAGE;
const loadSearchPage = async (page) => {
const loadSearchPage = async (page: number) => {
if (searching) return;
searching = true;
@ -146,11 +156,9 @@ export async function displaySearch(
: formatSearchResultList(searchResult.results);
const result = trimLines(`
${headerText}
\`\`\`js
${resultList}
\`\`\`
`);
${headerText}
${Formatters.codeBlock("js", resultList)}
`);
const searchMsg = await searchMsgPromise;
@ -300,7 +308,7 @@ async function performMemberSearch(
args: MemberSearchParams,
page = 1,
perPage = SEARCH_RESULTS_PER_PAGE,
): Promise<{ results: GuildMember[]; totalResults: number; page: number; lastPage: number; from: number; to: number }> {
): Promise<SearchResult<GuildMember>> {
await refreshMembersIfNeeded(pluginData.guild);
let matchingMembers = Array.from(pluginData.guild.members.cache.values());
@ -428,7 +436,7 @@ async function performBanSearch(
args: BanSearchParams,
page = 1,
perPage = SEARCH_RESULTS_PER_PAGE,
): Promise<{ results: User[]; totalResults: number; page: number; lastPage: number; from: number; to: number }> {
): Promise<SearchResult<User>> {
const member = pluginData.guild.members.cache.get(pluginData.client.user!.id);
if (member && !hasDiscordPermissions(member.permissions, Permissions.FLAGS.BAN_MEMBERS)) {
throw new SearchError(`Unable to search bans: missing "Ban Members" permission`);
@ -456,7 +464,7 @@ async function performBanSearch(
});
}
const [, sortDir, sortBy] = (args.sort && args.sort.match(/^(-?)(.*)$/)) ?? [null, "ASC", "name"];
const [, sortDir, sortBy] = args.sort?.match(/^(-?)(.*)$/) ?? [null, "ASC", "name"];
const realSortDir = sortDir === "-" ? "DESC" : "ASC";
if (sortBy === "id") {

View file

@ -1,17 +1,15 @@
import {
Client,
Constants,
Message,
MessageActionRow,
MessageButton,
MessageEditOptions,
MessageOptions,
MessageReaction,
PartialMessageReaction,
PartialUser,
TextChannel,
User,
} from "discord.js";
import { Awaitable } from "knub/dist/utils";
import { MINUTES, noop } from "../utils";
import Timeout = NodeJS.Timeout;
export type LoadPageFn = (page: number) => Awaitable<MessageOptions & MessageEditOptions>;
@ -25,8 +23,10 @@ const defaultOpts: PaginateMessageOpts = {
limitToUserId: null,
};
const forwardId = "forward" as const;
const backwardId = "backward" as const;
export async function createPaginatedMessage(
client: Client,
channel: TextChannel | User,
totalPages: number,
loadPageFn: LoadPageFn,
@ -34,30 +34,37 @@ export async function createPaginatedMessage(
): Promise<Message> {
const fullOpts = { ...defaultOpts, ...opts } as PaginateMessageOpts;
const firstPageContent = await loadPageFn(1);
const message = await channel.send(firstPageContent);
const components: MessageButton[] = [
new MessageButton({
customId: backwardId,
emoji: "⬅",
style: Constants.MessageButtonStyles.SECONDARY,
}),
new MessageButton({
customId: forwardId,
emoji: "➡",
style: Constants.MessageButtonStyles.SECONDARY,
}),
];
const message = await channel.send({ ...firstPageContent, components: [new MessageActionRow({ components })] });
let page = 1;
let pageLoadId = 0; // Used to avoid race conditions when rapidly switching pages
const reactionListener = async (
reactionMessage: MessageReaction | PartialMessageReaction,
reactor: User | PartialUser,
) => {
if (reactionMessage.message.id !== message.id) {
return;
const collector = message.createMessageComponentCollector({ time: fullOpts.timeout });
collector.on("collect", async (interaction) => {
if (fullOpts.limitToUserId && interaction.user.id !== fullOpts.limitToUserId) {
return interaction.reply({ content: `You are not permitted to use these buttons.`, ephemeral: true });
}
if (fullOpts.limitToUserId && reactor.id !== fullOpts.limitToUserId) {
return;
}
if (reactor.id === client.user!.id) {
return;
}
await interaction.deferUpdate();
let pageDelta = 0;
if (reactionMessage.emoji.name === "⬅️") {
if (interaction.customId === backwardId) {
pageDelta = -1;
} else if (reactionMessage.emoji.name === "➡️") {
} else if (interaction.customId === forwardId) {
pageDelta = 1;
}
@ -71,34 +78,12 @@ export async function createPaginatedMessage(
}
page = newPage;
const thisPageLoadId = ++pageLoadId;
const newPageContent = await loadPageFn(page);
if (thisPageLoadId !== pageLoadId) {
return;
}
void message.edit(await loadPageFn(page)).catch(noop);
});
message.edit(newPageContent).catch(noop);
reactionMessage.users.remove(reactor.id).catch(noop);
refreshTimeout();
};
client.on("messageReactionAdd", reactionListener);
// The timeout after which reactions are removed and the pagination stops working
// is refreshed each time the page is changed
let timeout: Timeout;
const refreshTimeout = () => {
clearTimeout(timeout);
timeout = setTimeout(() => {
message.reactions.removeAll().catch(noop);
client.off("messageReactionAdd", reactionListener);
}, fullOpts.timeout);
};
refreshTimeout();
// Add reactions
message.react("⬅️").catch(noop);
message.react("➡️").catch(noop);
collector.on("end", () => {
message.edit({ components: [] });
});
return message;
}