djs-selfbot-v13 3.7.29 → 3.7.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/client/Client.js +7 -0
- package/src/index.js +3 -0
- package/src/managers/BackupManager.js +141 -0
- package/src/managers/QuestManager.js +488 -100
- package/src/managers/backup/create.js +167 -0
- package/src/managers/backup/index.js +144 -0
- package/src/managers/backup/load.js +293 -0
- package/src/managers/backup/util.js +400 -0
- package/typings/index.d.ts +219 -20
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
fetchChannelPermissions,
|
|
5
|
+
fetchTextChannelData,
|
|
6
|
+
fetchVoiceChannelData,
|
|
7
|
+
fetchBuffer,
|
|
8
|
+
} = require('./util');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Returns banned members of the guild
|
|
12
|
+
* @param {import('../../structures/Guild').Guild} guild
|
|
13
|
+
* @returns {Promise<Object[]>}
|
|
14
|
+
*/
|
|
15
|
+
async function getBans(guild) {
|
|
16
|
+
const bans = [];
|
|
17
|
+
const cases = await guild.bans.fetch();
|
|
18
|
+
|
|
19
|
+
cases.forEach(ban => {
|
|
20
|
+
bans.push({
|
|
21
|
+
id: ban.user.id,
|
|
22
|
+
reason: ban.reason,
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return bans;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Returns members of the guild
|
|
31
|
+
* @param {import('../../structures/Guild').Guild} guild
|
|
32
|
+
* @returns {Promise<Object[]>}
|
|
33
|
+
*/
|
|
34
|
+
async function getMembers(guild) {
|
|
35
|
+
const members = [];
|
|
36
|
+
|
|
37
|
+
guild.members.cache.forEach(member => {
|
|
38
|
+
members.push({
|
|
39
|
+
userId: member.user.id,
|
|
40
|
+
username: member.user.username,
|
|
41
|
+
discriminator: member.user.discriminator,
|
|
42
|
+
avatarUrl: member.user.avatarURL(),
|
|
43
|
+
joinedTimestamp: member.joinedTimestamp,
|
|
44
|
+
roles: member.roles.cache.map(role => role.id),
|
|
45
|
+
bot: member.user.bot,
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return members;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Returns roles of the guild
|
|
54
|
+
* @param {import('../../structures/Guild').Guild} guild
|
|
55
|
+
* @returns {Promise<Object[]>}
|
|
56
|
+
*/
|
|
57
|
+
async function getRoles(guild) {
|
|
58
|
+
const roles = [];
|
|
59
|
+
|
|
60
|
+
guild.roles.cache
|
|
61
|
+
.filter(role => !role.managed)
|
|
62
|
+
.sort((a, b) => b.position - a.position)
|
|
63
|
+
.forEach(role => {
|
|
64
|
+
roles.push({
|
|
65
|
+
oldId: role.id,
|
|
66
|
+
name: role.name,
|
|
67
|
+
color: role.hexColor,
|
|
68
|
+
hoist: role.hoist,
|
|
69
|
+
permissions: role.permissions.bitfield.toString(),
|
|
70
|
+
mentionable: role.mentionable,
|
|
71
|
+
position: role.position,
|
|
72
|
+
isEveryone: guild.id === role.id,
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
return roles;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Returns emojis of the guild
|
|
81
|
+
* @param {import('../../structures/Guild').Guild} guild
|
|
82
|
+
* @param {Object} options
|
|
83
|
+
* @returns {Promise<Object[]>}
|
|
84
|
+
*/
|
|
85
|
+
async function getEmojis(guild, options) {
|
|
86
|
+
const emojis = [];
|
|
87
|
+
|
|
88
|
+
for (const emoji of guild.emojis.cache.values()) {
|
|
89
|
+
const emojiData = { name: emoji.name };
|
|
90
|
+
|
|
91
|
+
if (options.saveImages === 'base64') {
|
|
92
|
+
emojiData.base64 = (await fetchBuffer(emoji.url)).toString('base64');
|
|
93
|
+
} else {
|
|
94
|
+
emojiData.url = emoji.url;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
emojis.push(emojiData);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return emojis;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Fetch channel data based on type
|
|
105
|
+
* @param {import('../../structures/GuildChannel')} channel
|
|
106
|
+
* @param {Object} options
|
|
107
|
+
* @returns {Promise<Object>}
|
|
108
|
+
*/
|
|
109
|
+
async function fetchAnyChannelData(channel, options) {
|
|
110
|
+
if (['GUILD_TEXT', 'GUILD_NEWS'].includes(channel.type)) {
|
|
111
|
+
return fetchTextChannelData(channel, options);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return fetchVoiceChannelData(channel);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Returns channels of the guild
|
|
119
|
+
* @param {import('../../structures/Guild').Guild} guild
|
|
120
|
+
* @param {Object} options
|
|
121
|
+
* @returns {Promise<Object>}
|
|
122
|
+
*/
|
|
123
|
+
async function getChannels(guild, options) {
|
|
124
|
+
const allChannels = guild.channels.cache;
|
|
125
|
+
|
|
126
|
+
const categories = allChannels
|
|
127
|
+
.filter(ch => ch.type === 'GUILD_CATEGORY')
|
|
128
|
+
.sort((a, b) => a.position - b.position);
|
|
129
|
+
|
|
130
|
+
const categoryDataPromises = categories.map(async category => {
|
|
131
|
+
const children = allChannels
|
|
132
|
+
.filter(c => c.parentId === category.id)
|
|
133
|
+
.sort((a, b) => a.position - b.position);
|
|
134
|
+
|
|
135
|
+
const childrenData = await Promise.all(children.map(child => fetchAnyChannelData(child, options)));
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
name: category.name,
|
|
139
|
+
permissions: fetchChannelPermissions(category),
|
|
140
|
+
children: childrenData,
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const others = allChannels
|
|
145
|
+
.filter(
|
|
146
|
+
ch => !ch.parent && ch.type !== 'GUILD_CATEGORY' && !ch.isThread?.() && ch.type !== 'GUILD_STORE',
|
|
147
|
+
)
|
|
148
|
+
.sort((a, b) => a.position - b.position);
|
|
149
|
+
|
|
150
|
+
const [categoriesResult, othersResult] = await Promise.all([
|
|
151
|
+
Promise.all(categoryDataPromises),
|
|
152
|
+
Promise.all(others.map(ch => fetchAnyChannelData(ch, options))),
|
|
153
|
+
]);
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
categories: categoriesResult,
|
|
157
|
+
others: othersResult,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
module.exports = {
|
|
162
|
+
getBans,
|
|
163
|
+
getMembers,
|
|
164
|
+
getRoles,
|
|
165
|
+
getEmojis,
|
|
166
|
+
getChannels,
|
|
167
|
+
};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const SnowflakeUtil = require('../../util/SnowflakeUtil');
|
|
4
|
+
const createMaster = require('./create');
|
|
5
|
+
const loadMaster = require('./load');
|
|
6
|
+
const { clearGuild, fetchBuffer } = require('./util');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Creates a guild backup
|
|
10
|
+
* @param {import('../../structures/Guild').Guild} guild
|
|
11
|
+
* @param {Object} [options] Backup options
|
|
12
|
+
* @returns {Promise<Object>}
|
|
13
|
+
*/
|
|
14
|
+
async function create(guild, options = {}) {
|
|
15
|
+
const normalizedOptions = {
|
|
16
|
+
backupID: null,
|
|
17
|
+
maxMessagesPerChannel: 10,
|
|
18
|
+
doNotBackup: ['bans', 'emojis'],
|
|
19
|
+
backupMembers: false,
|
|
20
|
+
saveImages: '',
|
|
21
|
+
...options,
|
|
22
|
+
backupID: options.backupID ?? options.backupId ?? null,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const backupData = {
|
|
26
|
+
name: guild.name,
|
|
27
|
+
verificationLevel: guild.verificationLevel,
|
|
28
|
+
explicitContentFilter: guild.explicitContentFilter,
|
|
29
|
+
defaultMessageNotifications: guild.defaultMessageNotifications,
|
|
30
|
+
afk: guild.afkChannel ? { name: guild.afkChannel.name, timeout: guild.afkTimeout } : null,
|
|
31
|
+
widget: {
|
|
32
|
+
enabled: guild.widgetEnabled,
|
|
33
|
+
channel: guild.widgetChannel ? guild.widgetChannel.name : null,
|
|
34
|
+
},
|
|
35
|
+
community: {
|
|
36
|
+
enabled: guild.features.includes('COMMUNITY'),
|
|
37
|
+
systemChannelFlags: guild.systemChannelFlags ? guild.systemChannelFlags.bitfield : null,
|
|
38
|
+
systemChannelId: guild.systemChannelId,
|
|
39
|
+
rulesChannelId: guild.rulesChannelId,
|
|
40
|
+
publicUpdatesChannelId: guild.publicUpdatesChannelId,
|
|
41
|
+
safetyAlertsChannelId: guild.safetyAlertsChannelId || null,
|
|
42
|
+
},
|
|
43
|
+
channels: { categories: [], others: [] },
|
|
44
|
+
roles: [],
|
|
45
|
+
bans: [],
|
|
46
|
+
emojis: [],
|
|
47
|
+
members: [],
|
|
48
|
+
createdTimestamp: Date.now(),
|
|
49
|
+
guildID: guild.id,
|
|
50
|
+
id: normalizedOptions.backupID ?? SnowflakeUtil.generate(Date.now()),
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
if (guild.iconURL()) {
|
|
54
|
+
if (normalizedOptions.saveImages === 'base64') {
|
|
55
|
+
backupData.iconBase64 = (await fetchBuffer(guild.iconURL({ dynamic: true }))).toString('base64');
|
|
56
|
+
}
|
|
57
|
+
backupData.iconURL = guild.iconURL({ dynamic: true });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (guild.splashURL()) {
|
|
61
|
+
if (normalizedOptions.saveImages === 'base64') {
|
|
62
|
+
backupData.splashBase64 = (await fetchBuffer(guild.splashURL())).toString('base64');
|
|
63
|
+
}
|
|
64
|
+
backupData.splashURL = guild.splashURL();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (guild.bannerURL()) {
|
|
68
|
+
if (normalizedOptions.saveImages === 'base64') {
|
|
69
|
+
backupData.bannerBase64 = (await fetchBuffer(guild.bannerURL())).toString('base64');
|
|
70
|
+
}
|
|
71
|
+
backupData.bannerURL = guild.bannerURL();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (normalizedOptions.backupMembers) {
|
|
75
|
+
backupData.members = await createMaster.getMembers(guild);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!normalizedOptions.doNotBackup.includes('bans')) {
|
|
79
|
+
backupData.bans = await createMaster.getBans(guild);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (!normalizedOptions.doNotBackup.includes('roles')) {
|
|
83
|
+
backupData.roles = await createMaster.getRoles(guild);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!normalizedOptions.doNotBackup.includes('emojis')) {
|
|
87
|
+
backupData.emojis = await createMaster.getEmojis(guild, normalizedOptions);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!normalizedOptions.doNotBackup.includes('channels')) {
|
|
91
|
+
backupData.channels = await createMaster.getChannels(guild, normalizedOptions);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return backupData;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Loads a backup into a guild
|
|
99
|
+
* @param {Object} backupData
|
|
100
|
+
* @param {import('../../structures/Guild').Guild} guild
|
|
101
|
+
* @param {Object} [options] Load options
|
|
102
|
+
* @returns {Promise<Object>}
|
|
103
|
+
*/
|
|
104
|
+
async function load(backupData, guild, options = {}) {
|
|
105
|
+
if (!guild) throw new Error('Invalid guild');
|
|
106
|
+
|
|
107
|
+
const normalizedOptions = {
|
|
108
|
+
clearGuildBeforeRestore: true,
|
|
109
|
+
maxMessagesPerChannel: 10,
|
|
110
|
+
...options,
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
if (normalizedOptions.clearGuildBeforeRestore) {
|
|
114
|
+
await clearGuild(guild);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
await Promise.all([loadMaster.loadConfig(guild, backupData), loadMaster.loadRoles(guild, backupData)]);
|
|
118
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
119
|
+
await loadMaster.loadChannels(guild, backupData, normalizedOptions);
|
|
120
|
+
|
|
121
|
+
const restorePromises = [
|
|
122
|
+
loadMaster.loadAFK(guild, backupData),
|
|
123
|
+
loadMaster.loadEmbedChannel(guild, backupData),
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
if (!normalizedOptions.doNotBackup?.includes('emojis')) {
|
|
127
|
+
restorePromises.push(loadMaster.loadEmojis(guild, backupData));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (!normalizedOptions.doNotBackup?.includes('bans')) {
|
|
131
|
+
restorePromises.push(loadMaster.loadBans(guild, backupData));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
await Promise.all(restorePromises);
|
|
135
|
+
await loadMaster.loadCommunity(guild, backupData);
|
|
136
|
+
await loadMaster.loadRoleChannelPermissions(guild, backupData);
|
|
137
|
+
|
|
138
|
+
return backupData;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
module.exports = {
|
|
142
|
+
create,
|
|
143
|
+
load,
|
|
144
|
+
};
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Permissions = require('../../util/Permissions');
|
|
4
|
+
const { loadCategory, loadChannel } = require('./util');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Restores the guild configuration
|
|
8
|
+
* @param {import('../../structures/Guild').Guild} guild
|
|
9
|
+
* @param {Object} backupData
|
|
10
|
+
* @returns {Promise<void>}
|
|
11
|
+
*/
|
|
12
|
+
async function loadConfig(guild, backupData) {
|
|
13
|
+
const configPromises = [];
|
|
14
|
+
|
|
15
|
+
if (backupData.name) configPromises.push(guild.setName(backupData.name));
|
|
16
|
+
if (backupData.iconBase64) {
|
|
17
|
+
configPromises.push(guild.setIcon(Buffer.from(backupData.iconBase64, 'base64')));
|
|
18
|
+
} else if (backupData.iconURL) {
|
|
19
|
+
configPromises.push(guild.setIcon(backupData.iconURL));
|
|
20
|
+
}
|
|
21
|
+
if (backupData.splashBase64) {
|
|
22
|
+
configPromises.push(guild.setSplash(Buffer.from(backupData.splashBase64, 'base64')));
|
|
23
|
+
} else if (backupData.splashURL) {
|
|
24
|
+
configPromises.push(guild.setSplash(backupData.splashURL));
|
|
25
|
+
}
|
|
26
|
+
if (backupData.bannerBase64) {
|
|
27
|
+
configPromises.push(guild.setBanner(Buffer.from(backupData.bannerBase64, 'base64')));
|
|
28
|
+
} else if (backupData.bannerURL) {
|
|
29
|
+
configPromises.push(guild.setBanner(backupData.bannerURL));
|
|
30
|
+
}
|
|
31
|
+
if (backupData.verificationLevel) {
|
|
32
|
+
configPromises.push(guild.setVerificationLevel(backupData.verificationLevel));
|
|
33
|
+
}
|
|
34
|
+
if (backupData.defaultMessageNotifications) {
|
|
35
|
+
configPromises.push(guild.setDefaultMessageNotifications(backupData.defaultMessageNotifications));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const changeableExplicitLevel = guild.features.includes('COMMUNITY');
|
|
39
|
+
if (backupData.explicitContentFilter && changeableExplicitLevel) {
|
|
40
|
+
configPromises.push(guild.setExplicitContentFilter(backupData.explicitContentFilter));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
await Promise.all(configPromises);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Restore the guild roles
|
|
48
|
+
* @param {import('../../structures/Guild').Guild} guild
|
|
49
|
+
* @param {Object} backupData
|
|
50
|
+
* @returns {Promise<void>}
|
|
51
|
+
*/
|
|
52
|
+
async function loadRoles(guild, backupData) {
|
|
53
|
+
const rolePromises = [];
|
|
54
|
+
|
|
55
|
+
backupData.roles.forEach(roleData => {
|
|
56
|
+
if (roleData.isEveryone) {
|
|
57
|
+
rolePromises.push(
|
|
58
|
+
guild.roles.cache.get(guild.id).edit({
|
|
59
|
+
name: roleData.name,
|
|
60
|
+
colors: { primaryColor: roleData.color },
|
|
61
|
+
permissions: BigInt(roleData.permissions),
|
|
62
|
+
mentionable: roleData.mentionable,
|
|
63
|
+
}),
|
|
64
|
+
);
|
|
65
|
+
} else {
|
|
66
|
+
rolePromises.push(
|
|
67
|
+
guild.roles.create({
|
|
68
|
+
name: roleData.name,
|
|
69
|
+
colors: { primaryColor: roleData.color },
|
|
70
|
+
hoist: roleData.hoist,
|
|
71
|
+
permissions: BigInt(roleData.permissions),
|
|
72
|
+
mentionable: roleData.mentionable,
|
|
73
|
+
}),
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
await Promise.all(rolePromises);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Restore the guild channels
|
|
83
|
+
* @param {import('../../structures/Guild').Guild} guild
|
|
84
|
+
* @param {Object} backupData
|
|
85
|
+
* @param {Object} options
|
|
86
|
+
* @returns {Promise<void>}
|
|
87
|
+
*/
|
|
88
|
+
async function loadChannels(guild, backupData, options) {
|
|
89
|
+
const loadChannelPromises = [];
|
|
90
|
+
|
|
91
|
+
backupData.channels.categories.forEach(categoryData => {
|
|
92
|
+
if (!categoryData.name) return;
|
|
93
|
+
|
|
94
|
+
loadChannelPromises.push(
|
|
95
|
+
(async () => {
|
|
96
|
+
try {
|
|
97
|
+
const createdCategory = await loadCategory(categoryData, guild);
|
|
98
|
+
await Promise.all(
|
|
99
|
+
categoryData.children
|
|
100
|
+
.filter(channelData => channelData.name)
|
|
101
|
+
.map(channelData => loadChannel(channelData, guild, createdCategory, options)),
|
|
102
|
+
);
|
|
103
|
+
} catch {
|
|
104
|
+
// Continue restoring other categories
|
|
105
|
+
}
|
|
106
|
+
})(),
|
|
107
|
+
);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
backupData.channels.others.forEach(channelData => {
|
|
111
|
+
if (!channelData.name) return;
|
|
112
|
+
loadChannelPromises.push(loadChannel(channelData, guild, null, options));
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
await Promise.all(loadChannelPromises);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Restore the afk configuration
|
|
120
|
+
* @param {import('../../structures/Guild').Guild} guild
|
|
121
|
+
* @param {Object} backupData
|
|
122
|
+
* @returns {Promise<void>}
|
|
123
|
+
*/
|
|
124
|
+
async function loadAFK(guild, backupData) {
|
|
125
|
+
if (!backupData.afk) return;
|
|
126
|
+
|
|
127
|
+
await Promise.all([
|
|
128
|
+
guild.setAFKChannel(
|
|
129
|
+
guild.channels.cache.find(ch => ch.name === backupData.afk.name && ch.type === 'GUILD_VOICE'),
|
|
130
|
+
),
|
|
131
|
+
guild.setAFKTimeout(backupData.afk.timeout),
|
|
132
|
+
]);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Restore guild emojis
|
|
137
|
+
* @param {import('../../structures/Guild').Guild} guild
|
|
138
|
+
* @param {Object} backupData
|
|
139
|
+
* @returns {Promise<void>}
|
|
140
|
+
*/
|
|
141
|
+
async function loadEmojis(guild, backupData) {
|
|
142
|
+
await Promise.all(
|
|
143
|
+
backupData.emojis.map(emoji => {
|
|
144
|
+
if (emoji.url) return guild.emojis.create(emoji.url, emoji.name);
|
|
145
|
+
if (emoji.base64) return guild.emojis.create(Buffer.from(emoji.base64, 'base64'), emoji.name);
|
|
146
|
+
return Promise.resolve();
|
|
147
|
+
}),
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Restore guild bans
|
|
153
|
+
* @param {import('../../structures/Guild').Guild} guild
|
|
154
|
+
* @param {Object} backupData
|
|
155
|
+
* @returns {Promise<void>}
|
|
156
|
+
*/
|
|
157
|
+
async function loadBans(guild, backupData) {
|
|
158
|
+
await Promise.all(
|
|
159
|
+
backupData.bans.map(ban =>
|
|
160
|
+
guild.members.ban(ban.id, {
|
|
161
|
+
reason: ban.reason,
|
|
162
|
+
}),
|
|
163
|
+
),
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Restore embed channel configuration
|
|
169
|
+
* @param {import('../../structures/Guild').Guild} guild
|
|
170
|
+
* @param {Object} backupData
|
|
171
|
+
* @returns {Promise<void>}
|
|
172
|
+
*/
|
|
173
|
+
async function loadEmbedChannel(guild, backupData) {
|
|
174
|
+
if (!backupData.widget.channel) return;
|
|
175
|
+
|
|
176
|
+
await guild.setWidgetSettings({
|
|
177
|
+
enabled: backupData.widget.enabled,
|
|
178
|
+
channel: guild.channels.cache.find(ch => ch.name === backupData.widget.channel),
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Restore community settings
|
|
184
|
+
* @param {import('../../structures/Guild').Guild} guild
|
|
185
|
+
* @param {Object} backupData
|
|
186
|
+
* @returns {Promise<void>}
|
|
187
|
+
*/
|
|
188
|
+
async function loadCommunity(guild, backupData) {
|
|
189
|
+
if (!backupData.community) return;
|
|
190
|
+
|
|
191
|
+
const rulesChannelData =
|
|
192
|
+
backupData.channels.categories.find(c => c.children.find(ch => ch.rulesChannel))?.children.find(
|
|
193
|
+
ch => ch.rulesChannel,
|
|
194
|
+
) || backupData.channels.others.find(c => c.rulesChannel);
|
|
195
|
+
const publicUpdatesChannelData =
|
|
196
|
+
backupData.channels.categories
|
|
197
|
+
.find(c => c.children.find(ch => ch.publicUpdatesChannel))
|
|
198
|
+
?.children.find(ch => ch.publicUpdatesChannel) ||
|
|
199
|
+
backupData.channels.others.find(c => c.publicUpdatesChannel);
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
const isCommunityEnabled = guild.features.includes('COMMUNITY');
|
|
203
|
+
const shouldBeCommunityEnabled = backupData.community.enabled;
|
|
204
|
+
|
|
205
|
+
if (shouldBeCommunityEnabled && !isCommunityEnabled) {
|
|
206
|
+
const rulesChannel =
|
|
207
|
+
rulesChannelData &&
|
|
208
|
+
guild.channels.cache.find(ch => ch.name === rulesChannelData.name && ch.type === 'GUILD_TEXT');
|
|
209
|
+
const publicUpdatesChannel =
|
|
210
|
+
publicUpdatesChannelData &&
|
|
211
|
+
guild.channels.cache
|
|
212
|
+
.filter(
|
|
213
|
+
ch =>
|
|
214
|
+
ch.name === publicUpdatesChannelData.name &&
|
|
215
|
+
ch.type === 'GUILD_TEXT' &&
|
|
216
|
+
ch.id !== rulesChannel?.id,
|
|
217
|
+
)
|
|
218
|
+
.first();
|
|
219
|
+
|
|
220
|
+
if (rulesChannel && publicUpdatesChannel) {
|
|
221
|
+
await guild.setCommunity(true, publicUpdatesChannel, rulesChannel, 'Backup');
|
|
222
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
223
|
+
}
|
|
224
|
+
} else if (shouldBeCommunityEnabled && isCommunityEnabled) {
|
|
225
|
+
const currentRulesChannel = guild.rulesChannel;
|
|
226
|
+
const currentPublicUpdatesChannel = guild.publicUpdatesChannel;
|
|
227
|
+
|
|
228
|
+
const newRulesChannel =
|
|
229
|
+
rulesChannelData && guild.channels.cache.find(ch => ch.name === rulesChannelData.name);
|
|
230
|
+
const newPublicUpdatesChannel =
|
|
231
|
+
publicUpdatesChannelData &&
|
|
232
|
+
guild.channels.cache.find(ch => ch.name === publicUpdatesChannelData.name);
|
|
233
|
+
|
|
234
|
+
const rulesChannelChanged = newRulesChannel && currentRulesChannel?.id !== newRulesChannel.id;
|
|
235
|
+
const updatesChannelChanged =
|
|
236
|
+
newPublicUpdatesChannel && currentPublicUpdatesChannel?.id !== newPublicUpdatesChannel.id;
|
|
237
|
+
|
|
238
|
+
if ((rulesChannelChanged || updatesChannelChanged) && newRulesChannel && newPublicUpdatesChannel) {
|
|
239
|
+
await guild.setRulesChannel(newRulesChannel.id).catch(() => false);
|
|
240
|
+
await guild.setPublicUpdatesChannel(newPublicUpdatesChannel.id).catch(() => false);
|
|
241
|
+
currentPublicUpdatesChannel?.delete().catch(() => false);
|
|
242
|
+
currentRulesChannel?.delete().catch(() => false);
|
|
243
|
+
}
|
|
244
|
+
} else if (!shouldBeCommunityEnabled && isCommunityEnabled) {
|
|
245
|
+
await guild.setCommunity(false, null, null, 'Backup');
|
|
246
|
+
}
|
|
247
|
+
} catch {
|
|
248
|
+
// Ignore community restore errors
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Restore role channel permissions
|
|
254
|
+
* @param {import('../../structures/Guild').Guild} guild
|
|
255
|
+
* @param {Object} backupData
|
|
256
|
+
* @returns {Promise<void>}
|
|
257
|
+
*/
|
|
258
|
+
async function loadRoleChannelPermissions(guild, backupData) {
|
|
259
|
+
for (const roleData of backupData.roles) {
|
|
260
|
+
if (!roleData.channelPermissions) continue;
|
|
261
|
+
|
|
262
|
+
let role = guild.roles.cache.find(r => r.name === roleData.name);
|
|
263
|
+
if (!role && roleData.isEveryone) role = guild.roles.cache.get(guild.id);
|
|
264
|
+
if (!role) continue;
|
|
265
|
+
|
|
266
|
+
for (const [channelName, permissions] of Object.entries(roleData.channelPermissions)) {
|
|
267
|
+
const channel = guild.channels.cache.find(c => c.name === channelName);
|
|
268
|
+
if (!channel) continue;
|
|
269
|
+
|
|
270
|
+
try {
|
|
271
|
+
await channel.permissionOverwrites.edit(role.id, {
|
|
272
|
+
allow: Permissions.resolve(permissions.allow),
|
|
273
|
+
deny: Permissions.resolve(permissions.deny),
|
|
274
|
+
});
|
|
275
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
276
|
+
} catch {
|
|
277
|
+
// Continue with next permission
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
module.exports = {
|
|
284
|
+
loadConfig,
|
|
285
|
+
loadRoles,
|
|
286
|
+
loadChannels,
|
|
287
|
+
loadAFK,
|
|
288
|
+
loadEmojis,
|
|
289
|
+
loadBans,
|
|
290
|
+
loadEmbedChannel,
|
|
291
|
+
loadCommunity,
|
|
292
|
+
loadRoleChannelPermissions,
|
|
293
|
+
};
|