1 |
/** |
2 |
* This file is part of SudoBot. |
3 |
* |
4 |
* Copyright (C) 2021-2022 OSN Inc. |
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 fs from 'fs'; |
21 |
import DiscordClient from '../client/Client'; |
22 |
import { GuildMember, Message, CommandInteraction, MessageEmbed, ContextMenuInteraction, Interaction } from 'discord.js'; |
23 |
import Axios, { AxiosRequestHeaders } from 'axios'; |
24 |
import { formatDistanceToNowStrict, formatDuration, intervalToDuration } from 'date-fns'; |
25 |
|
26 |
export function isDisabledServer(gid: string) { |
27 |
return !!DiscordClient.client.config.props[gid].disabled; |
28 |
} |
29 |
|
30 |
export function parseEmbedsInString(content: string) { |
31 |
const embedExpressions = content.matchAll(/embed\:(\{[^\n]+\})/g); |
32 |
const newContent = content.replace(/embed\:(\{[^\n]+\})/g, ''); |
33 |
let embeds: MessageEmbed[] = []; |
34 |
|
35 |
for (const expr of [...embedExpressions]) { |
36 |
const parsed = JSON.parse(expr[1]); |
37 |
|
38 |
try { |
39 |
embeds.push(new MessageEmbed(parsed).setColor(parsed.color)); |
40 |
} |
41 |
catch (e) { |
42 |
console.log(e); |
43 |
} |
44 |
} |
45 |
|
46 |
return { embeds, content: newContent }; |
47 |
} |
48 |
|
49 |
export function splitMessage(message: string, limit: number = 1000, maxIterationCount: number = 100) { |
50 |
const splitted: string[] = []; |
51 |
let content = message; |
52 |
let { length } = content; |
53 |
|
54 |
if (length >= limit) { |
55 |
let i = 0; |
56 |
|
57 |
while (length !== 0 && content !== '') { |
58 |
splitted.push(content.substring(0, limit)); |
59 |
content = content.substring(limit); |
60 |
length = content.length; |
61 |
i++; |
62 |
|
63 |
if (i >= maxIterationCount) { |
64 |
console.log('Break loop'); |
65 |
break; |
66 |
} |
67 |
} |
68 |
} |
69 |
else { |
70 |
splitted.push(message); |
71 |
} |
72 |
|
73 |
return splitted; |
74 |
} |
75 |
|
76 |
export function getHomeGuild(client: DiscordClient) { |
77 |
return client.guilds.cache.get(client.config.props.global.id); |
78 |
} |
79 |
|
80 |
export function shouldNotModerate(client: DiscordClient, member: GuildMember) { |
81 |
if (client.config.props.global.owners.includes(member.user.id)) { |
82 |
return false; |
83 |
} |
84 |
|
85 |
if (!client.config.props[member.guild.id].admin) { |
86 |
return false; |
87 |
} |
88 |
|
89 |
const role = client.config.props[member.guild.id].admin; |
90 |
|
91 |
return role && role.trim() !== '' && member.roles.cache.has(role); |
92 |
} |
93 |
|
94 |
export async function hasPermission(client: DiscordClient, member: GuildMember, msg: Message | CommandInteraction | ContextMenuInteraction, mod: GuildMember | null, error: string | null = "You don't have permission to moderate this user") { |
95 |
let m = mod; |
96 |
|
97 |
if (!m) { |
98 |
m = msg.member! as GuildMember; |
99 |
} |
100 |
|
101 |
if (client.config.props.global.owners.includes(m.user.id)) { |
102 |
return true; |
103 |
} |
104 |
|
105 |
if (member.id === m.id || member.roles.highest?.position >= m.roles.highest?.position) { |
106 |
if (error) { |
107 |
if (msg instanceof Interaction && msg.deferred) { |
108 |
await msg.editReply({ |
109 |
embeds: [ |
110 |
new MessageEmbed() |
111 |
.setColor('#f14a60') |
112 |
.setDescription(`:x: ${error}`) |
113 |
] |
114 |
}); |
115 |
|
116 |
return false; |
117 |
} |
118 |
|
119 |
await msg.reply({ |
120 |
embeds: [ |
121 |
new MessageEmbed() |
122 |
.setColor('#f14a60') |
123 |
.setDescription(`:x: ${error}`) |
124 |
] |
125 |
}); |
126 |
} |
127 |
|
128 |
return false; |
129 |
} |
130 |
|
131 |
return true; |
132 |
} |
133 |
|
134 |
export function timeProcess(seconds: number) { |
135 |
return formatDuration(intervalToDuration({ start: 0, end: seconds * 1000 })); |
136 |
} |
137 |
|
138 |
|
139 |
/** |
140 |
* @deprecated |
141 |
*/ |
142 |
export function timeProcessOld(seconds: number) { |
143 |
let interval = seconds / (60 * 60 * 24 * 30 * 365); |
144 |
|
145 |
if (interval >= 1) { |
146 |
return Math.floor(interval) + " year" + (Math.floor(interval) === 1 ? '' : 's'); |
147 |
} |
148 |
|
149 |
interval = seconds / (60 * 60 * 24 * 30); |
150 |
|
151 |
if (interval >= 1) { |
152 |
return Math.floor(interval) + " month" + (Math.floor(interval) === 1 ? '' : 's'); |
153 |
} |
154 |
|
155 |
interval = seconds / (60 * 60 * 24); |
156 |
|
157 |
if (interval >= 1) { |
158 |
return Math.floor(interval) + " day" + (Math.floor(interval) === 1 ? '' : 's'); |
159 |
} |
160 |
|
161 |
interval = seconds / (60 * 60); |
162 |
|
163 |
if (interval >= 1) { |
164 |
return Math.floor(interval) + " hour" + (Math.floor(interval) === 1 ? '' : 's'); |
165 |
} |
166 |
|
167 |
interval = seconds / 60; |
168 |
|
169 |
if (interval >= 1) { |
170 |
return Math.floor(interval) + " minute" + (Math.floor(interval) === 1 ? '' : 's'); |
171 |
} |
172 |
|
173 |
interval = seconds; |
174 |
|
175 |
return Math.floor(interval) + " second" + (Math.floor(interval) === 1 ? '' : 's'); |
176 |
} |
177 |
|
178 |
export function escapeRegex(string: string) { |
179 |
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); |
180 |
} |
181 |
|
182 |
export function timeSince(date: number) { |
183 |
// const seconds = Math.floor((Date.now() - date) / 1000); |
184 |
// return timeProcess(seconds) + ' ago'; |
185 |
return formatDistanceToNowStrict(new Date(date), { addSuffix: true }); |
186 |
} |
187 |
|
188 |
export async function download(url: string, path: string, headers?: AxiosRequestHeaders) { |
189 |
const writer = fs.createWriteStream(path); |
190 |
|
191 |
const response = await Axios({ |
192 |
url, |
193 |
method: 'GET', |
194 |
responseType: 'stream', |
195 |
headers |
196 |
}); |
197 |
|
198 |
response.data.pipe(writer); |
199 |
|
200 |
return new Promise((resolve, reject) => { |
201 |
if (response.status !== 200) { |
202 |
reject(); |
203 |
} |
204 |
|
205 |
writer.on('finish', resolve); |
206 |
writer.on('error', reject); |
207 |
}); |
208 |
} |
209 |
|
210 |
export async function deleteFile(path: string) { |
211 |
fs.rm(path, (err: any) => { |
212 |
if (err) { |
213 |
throw new Error(err); |
214 |
} |
215 |
}); |
216 |
} |
217 |
|
218 |
export function random(arr: Array <any>) { |
219 |
let index = Math.floor(Math.random() * arr.length); |
220 |
return arr[index]; |
221 |
} |
222 |
|
223 |
export function fill(length: number, string: string, token: string = ' ') { |
224 |
let safe = 0; |
225 |
|
226 |
if (length < string.length) |
227 |
return string; |
228 |
|
229 |
const diff = length - string.length; |
230 |
|
231 |
for (let i = 1; i <= diff; i++, safe++) { |
232 |
if (safe >= 500) |
233 |
break; |
234 |
|
235 |
string += ' '; |
236 |
} |
237 |
|
238 |
return string; |
239 |
} |
240 |
|
241 |
export function green(string: string) { |
242 |
return '\u001b[1;32m' + string + '\u001b[0m'; |
243 |
} |
244 |
|
245 |
export function yellow(string: string) { |
246 |
return '\u001b[1;33m' + string + '\u001b[0m'; |
247 |
} |
248 |
|
249 |
export function red(string: string) { |
250 |
return '\u001b[1;31m' + string + '\u001b[0m'; |
251 |
} |
252 |
|
253 |
export function generateInfractionDescription(client: DiscordClient, guildId: string, key: 'warning_message' | 'ban_message' | 'kick_message' | 'mute_message') { |
254 |
if (!client.config.props[guildId].infractions) { |
255 |
return undefined; |
256 |
} |
257 |
|
258 |
const message = client.config.props[guildId].infractions[key] || client.config.props[guildId!].infractions.common_message ? |
259 |
`${client.config.props[guildId].infractions.common_message ?? ''}${client.config.props[guildId!].infractions[key] && client.config.props[guildId!].infractions.common_message ? '\n' : ''}${client.config.props[guildId!].infractions[key] ?? ''}` |
260 |
: undefined; |
261 |
|
262 |
if (message && message.trim() === '') { |
263 |
return undefined; |
264 |
} |
265 |
|
266 |
return message; |
267 |
} |
268 |
|
269 |
export function hasConfig(client: DiscordClient, guildId: string, key: string) { |
270 |
return !!client.config.props[guildId][key]; |
271 |
} |