/[sudobot]/branches/6.x/src/utils/utils.ts
ViewVC logotype

Annotation of /branches/6.x/src/utils/utils.ts

Parent Directory Parent Directory | Revision Log Revision Log


Revision 577 - (hide annotations)
Mon Jul 29 18:52:37 2024 UTC (8 months ago) by rakinar2
File MIME type: application/typescript
File size: 9151 byte(s)
chore: add old version archive branches (2.x to 9.x-dev)
1 rakinar2 577 /**
2     * This file is part of SudoBot.
3     *
4     * Copyright (C) 2021-2023 OSN Developers.
5     *
6     * SudoBot is free software; you can redistribute it and/or modify it
7     * under the terms of the GNU Affero General Public License as published by
8     * the Free Software Foundation, either version 3 of the License, or
9     * (at your option) any later version.
10     *
11     * SudoBot is distributed in the hope that it will be useful, but
12     * WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU Affero General Public License for more details.
15     *
16     * You should have received a copy of the GNU Affero General Public License
17     * along with SudoBot. If not, see <https://www.gnu.org/licenses/>.
18     */
19    
20     import {
21     APIEmbedField,
22     Channel,
23     ChannelType,
24     ColorResolvable,
25     ComponentEmojiResolvable,
26     EmbedBuilder,
27     GuildEmoji,
28     GuildMember,
29     NewsChannel,
30     PermissionOverwrites,
31     PermissionResolvable,
32     PermissionsBitField,
33     TextBasedChannel,
34     TextChannel,
35     ThreadChannel,
36     User,
37     escapeMarkdown
38     } from "discord.js";
39     import { mkdirSync } from "fs";
40     import path from "path";
41     import Client from "../core/Client";
42     import { ActionDoneName } from "../services/InfractionManager";
43     import { userInfo } from "./embed";
44    
45     export function isSnowflake(input: string) {
46     return /^\d{16,22}$/.test(input);
47     }
48    
49     export function pick<T, K extends Array<keyof T>>(object: T, keys: K): Pick<T, K extends Array<infer E> ? E : never> {
50     if (typeof object === "object" && object !== null) {
51     const picked: Partial<T> = {};
52    
53     for (const key of keys) {
54     picked[key] = object[key];
55     }
56    
57     return picked as Pick<T, K extends Array<infer E> ? E : never>;
58     }
59    
60     return {} as Pick<T, K extends Array<infer E> ? E : never>;
61     }
62    
63     export interface CreateModerationEmbedOptions {
64     user: User;
65     moderator: User;
66     actionDoneName?: ActionDoneName;
67     reason?: string;
68     description?: string;
69     fields?:
70     | APIEmbedField[]
71     | ((fields: APIEmbedField[], id: string, reason?: string) => Promise<APIEmbedField[]> | APIEmbedField[]);
72     id: string | number;
73     color?: ColorResolvable;
74     }
75    
76     export async function createModerationEmbed({
77     user,
78     actionDoneName,
79     reason,
80     description,
81     fields,
82     id,
83     color = 0xf14a60,
84     moderator
85     }: CreateModerationEmbedOptions) {
86     return new EmbedBuilder({
87     author: {
88     name: user.tag,
89     icon_url: user.displayAvatarURL()
90     },
91     description: description ?? `**${escapeMarkdown(user.tag)}** has been ${actionDoneName}.`,
92     fields:
93     typeof fields === "function"
94     ? await fields(
95     [
96     {
97     name: "Reason",
98     value: reason ?? "*No reason provided*"
99     },
100     {
101     name: "User",
102     value: userInfo(user)
103     },
104     {
105     name: "Moderator",
106     value: userInfo(moderator)
107     },
108     {
109     name: "Infraction ID",
110     value: `${id}`
111     }
112     ],
113     `${id}`,
114     reason
115     )
116     : [
117     {
118     name: "Reason",
119     value: reason ?? "*No reason provided*"
120     },
121     {
122     name: "User",
123     value: userInfo(user)
124     },
125     {
126     name: "Moderator",
127     value: userInfo(moderator)
128     },
129     ...(fields ?? []),
130     {
131     name: "Infraction ID",
132     value: `${id}`
133     }
134     ],
135     footer: actionDoneName
136     ? {
137     text: actionDoneName[0].toUpperCase() + actionDoneName.substring(1)
138     }
139     : undefined
140     })
141     .setTimestamp()
142     .setColor(color);
143     }
144    
145     export function getEmoji<B extends boolean = false>(
146     client: Client,
147     name: string,
148     returnNull: B = false as B
149     ): B extends false ? string : string | null {
150     return (
151     client.guilds.cache
152     .get(process.env.HOME_GUILD_ID!)
153     ?.emojis.cache.find(e => e.name === name)
154     ?.toString() ??
155     client.configManager.systemConfig.emojis?.[name] ??
156     client.emojiMap.get(name)?.toString() ??
157     (returnNull ? null : "")
158     );
159     }
160    
161     export function getEmojiObject(client: Client, name: string): GuildEmoji | null {
162     return (
163     client.guilds.cache.get(process.env.HOME_GUILD_ID!)?.emojis.cache.find(e => e.name === name) ??
164     client.emojiMap.get(name) ??
165     null
166     );
167     }
168    
169     export function getComponentEmojiResolvable(client: Client, name: string): ComponentEmojiResolvable | null {
170     const emoji = getEmojiObject(client, name);
171    
172     return emoji
173     ? {
174     id: emoji?.id,
175     name: emoji?.name ?? emoji?.identifier,
176     animated: emoji?.animated ?? false
177     }
178     : null;
179     }
180    
181     export function isTextableChannel(
182     channel: Channel | ThreadChannel,
183     DMs = false
184     ): channel is TextChannel | NewsChannel | ThreadChannel {
185     return [
186     ...(DMs ? [ChannelType.DM, ChannelType.GroupDM] : []),
187     ChannelType.GuildAnnouncement,
188     ChannelType.GuildText,
189     ChannelType.PrivateThread,
190     ChannelType.PublicThread,
191     ChannelType.GuildVoice
192     ].includes(channel.type);
193     }
194    
195     export function developmentMode() {
196     return (
197     ["dev", "development"].includes(process.env.NODE_ENV?.toLowerCase()!) ||
198     ["dev", "development"].includes(process.env.SUDO_ENV?.toLowerCase()!)
199     );
200     }
201    
202     export function isImmuneToAutoMod(
203     client: Client,
204     member: GuildMember,
205     permission?: PermissionResolvable[] | PermissionResolvable
206     ) {
207     return client.permissionManager.isImmuneToAutoMod(member, permission);
208     }
209    
210     export function wait(time: number) {
211     return new Promise(resolve => setTimeout(resolve, time));
212     }
213    
214     export function sudoPrefix(pathLike: string, createDirIfNotExists = false) {
215     const directoryOrFile = path.resolve(process.env.SUDO_PREFIX ?? __dirname, process.env.SUDO_PREFIX ? "" : "../..", pathLike);
216    
217     if (createDirIfNotExists) mkdirSync(directoryOrFile, { recursive: true });
218    
219     return directoryOrFile;
220     }
221    
222     export function getPermissionNames(permissionsBit: bigint) {
223     const result = [];
224     const permissions = new PermissionsBitField(permissionsBit);
225    
226     for (const permission of Object.keys(PermissionsBitField.Flags) as (keyof typeof PermissionsBitField.Flags)[]) {
227     if (permissions.has(PermissionsBitField.Flags[permission])) {
228     result.push(permission);
229     }
230     }
231    
232     return result;
233     }
234    
235     export function forceGetPermissionNames(permissions: PermissionResolvable[]) {
236     const strings: string[] = [];
237    
238     for (const permission of permissions) {
239     if (typeof permission === "bigint") {
240     strings.push(...getPermissionNames(permission));
241     } else if (typeof permission === "string") {
242     strings.push(permission);
243     } else throw new Error("Unknown permission type");
244     }
245    
246     return strings;
247     }
248    
249     export function getChannelPermissionOverride(permission: PermissionResolvable, permissionOverwrites: PermissionOverwrites) {
250     return permissionOverwrites.allow.has(permission, true)
251     ? true
252     : permissionOverwrites.deny.has(permission, true)
253     ? true
254     : null;
255     }
256    
257     export function chunkedString(str: string, chunkSize = 4000) {
258     let output = [];
259     let chunk = "";
260    
261     for (let i = 0; i < str.length; i++) {
262     if (i !== 0 && i % chunkSize === 0) {
263     output.push(chunk);
264     chunk = str[i];
265     continue;
266     }
267    
268     chunk += str[i];
269     }
270    
271     if (chunk.length !== 0) {
272     output.push(chunk);
273     }
274    
275     return output;
276     }
277    
278     export function escapeRegex(string: string) {
279     return string.replace(/[/\-\\^$*+?.()|[\]{}]/g, "\\$&");
280     }
281    
282     export function safeMessageContent(content: string, member: GuildMember, channel?: TextBasedChannel) {
283     return member.permissions.has("MentionEveryone") &&
284     (!channel || member.permissionsIn(channel as TextChannel).has("MentionEveryone"))
285     ? content
286     : content
287     .replaceAll(/@everyone/gi, "`@everyone`")
288     .replaceAll(/@here/gi, "`@here`")
289     .replaceAll(`<@&${member.guild.id}>`, "`@everyone`")
290     .replace(/<@&(\d+)>/gim, (_, id) => `@${member.guild.roles.cache.get(id)?.name ?? id}`);
291     }
292    
293     export function isSystemAdmin(client: Client, userId: string) {
294     return client.configManager.systemConfig.system_admins.includes(userId);
295     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26