Migrate to revolt.js 7.0

This commit is contained in:
Lea 2023-04-12 21:17:34 +02:00
parent 9685bc5608
commit b3ee6094ce
Signed by: Lea
GPG key ID: 1BAFFE8347019C42
55 changed files with 873 additions and 879 deletions

4
.gitmodules vendored Normal file
View file

@ -0,0 +1,4 @@
[submodule "revolt.js"]
path = revolt.js
url = https://github.com/revoltchat/revolt.js
branch = insert/feat/store-rewrite

View file

@ -13,7 +13,6 @@
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@janderedev/revolt.js": "latest",
"@types/monk": "^6.0.0", "@types/monk": "^6.0.0",
"automod": "^0.1.0", "automod": "^0.1.0",
"axios": "^0.22.0", "axios": "^0.22.0",
@ -24,7 +23,8 @@
"log75": "^2.2.0", "log75": "^2.2.0",
"monk": "^7.3.4", "monk": "^7.3.4",
"prom-client": "^14.0.1", "prom-client": "^14.0.1",
"revolt-api": "^0.5.16", "revolt-api": "latest",
"revolt.js": "^7.0.0",
"ulid": "^2.3.0", "ulid": "^2.3.0",
"xlsx": "^0.17.3" "xlsx": "^0.17.3"
}, },
@ -33,6 +33,7 @@
}, },
"packageManager": "yarn@3.2.1", "packageManager": "yarn@3.2.1",
"resolutions": { "resolutions": {
"automod": "portal:../lib" "automod": "portal:../lib",
"revolt.js": "portal:../revolt.js"
} }
} }

View file

@ -5,7 +5,7 @@ import { commands, DEFAULT_PREFIX, ownerIDs } from "../../modules/command_handle
import child_process from 'child_process'; import child_process from 'child_process';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import { User } from "@janderedev/revolt.js/dist/maps/Users"; import { User } from "revolt.js";
import { adminBotLog } from "../../logging"; import { adminBotLog } from "../../logging";
import CommandCategory from "../../../struct/commands/CommandCategory"; import CommandCategory from "../../../struct/commands/CommandCategory";
import { getMutualServers, parseUserOrId } from "../../util"; import { getMutualServers, parseUserOrId } from "../../util";
@ -17,11 +17,11 @@ const BLACKLIST_MESSAGE = (username: string) => `\`@${username}\` has been banne
const sudoOverrides: { [key: string]: number|null } = {} const sudoOverrides: { [key: string]: number|null } = {}
const isSudo = (user: User): boolean => { const isSudo = (user: User): boolean => {
return !!(sudoOverrides[user._id] && sudoOverrides[user._id]! > Date.now()); return !!(sudoOverrides[user.id] && sudoOverrides[user.id]! > Date.now());
} }
const updateSudoTimeout = (user: User) => { const updateSudoTimeout = (user: User) => {
sudoOverrides[user._id] = Date.now() + (1000 * 60 * 5); sudoOverrides[user.id] = Date.now() + (1000 * 60 * 5);
} }
const getCommitHash = (): Promise<string|null> => new Promise((resolve) => { const getCommitHash = (): Promise<string|null> => new Promise((resolve) => {
@ -57,23 +57,22 @@ export default {
const pjson = JSON.parse((await fs.promises.readFile(path.join(process.cwd(), 'package.json'))).toString()); const pjson = JSON.parse((await fs.promises.readFile(path.join(process.cwd(), 'package.json'))).toString());
let msg = `# AutoMod stats\n` let msg = `# AutoMod stats\n`
+ `### Cache\n` + `### Cache\n`
+ `Servers: \`${client.servers.size}\`\n` + `Servers: \`${client.servers.size()}\`\n`
+ `Channels: \`${client.channels.size}\`\n` + `Channels: \`${client.channels.size()}\`\n`
+ `Users: \`${client.users.size}\`\n` + `Users: \`${client.users.size()}\`\n`
+ `### Misc\n` + `### Misc\n`
+ `Command count: \`${commands.length}\`\n` + `Command count: \`${commands.length}\`\n`
+ `Environment: \`${process.env.NODE_ENV || 'testing'}\`\n` + `Environment: \`${process.env.NODE_ENV || 'testing'}\`\n`
+ `Commit hash: \`${await getCommitHash() || 'Unknown'}\`\n` + `Commit hash: \`${await getCommitHash() || 'Unknown'}\`\n`
+ `### Packages\n` + `### Packages\n`
+ `revolt.js: \`${pjson.dependencies['@janderedev/revolt.js']}\`\n` + `revolt.js: \`${pjson.dependencies['revolt.js']}\`\n`
+ `discord.js: \`${pjson.dependencies['discord.js']}\`\n` + `discord.js: \`${pjson.dependencies['discord.js']}\`\n`
+ `axios: \`${pjson.dependencies['axios']}\`\n` + `axios: \`${pjson.dependencies['axios']}\`\n`
+ `log75: \`${pjson.dependencies['log75']}\`\n` + `log75: \`${pjson.dependencies['log75']}\`\n`
+ `typescript: \`${pjson.devDependencies['typescript']}\`\n` + `typescript: \`${pjson.devDependencies['typescript']}\`\n`
+ `### Connection\n` + `### Connection\n`
+ `API Endpoint: \`${client.apiURL}\`\n` + `API Endpoint: \`${client.options.baseURL}\`\n`
+ `Heartbeat: \`${client.heartbeat}\`\n` + `Ping: \`${client.events.ping() ?? 'Unknown'}\`\n`
+ `Ping: \`${client.websocket.ping ?? 'Unknown'}\`\n`
+ `### Bot configuration\n` + `### Bot configuration\n`
+ `Owners: \`${ownerIDs.length}\` (${ownerIDs.join(', ')})\n`; + `Owners: \`${ownerIDs.length}\` (${ownerIDs.join(', ')})\n`;
@ -87,7 +86,7 @@ export default {
case 'on': { case 'on': {
if (isSudo(message.author!)) return message.reply('You are already in sudo mode!'); if (isSudo(message.author!)) return message.reply('You are already in sudo mode!');
sudoOverrides[message.author_id] = Date.now() + (1000 * 60 * 5); sudoOverrides[message.authorId!] = Date.now() + (1000 * 60 * 5);
let msg = `# %emoji% Sudo mode enabled\n` let msg = `# %emoji% Sudo mode enabled\n`
+ `In sudo mode, you will be able to run any command regardless of your server permissions.\n` + `In sudo mode, you will be able to run any command regardless of your server permissions.\n`
@ -106,7 +105,7 @@ export default {
case 'off': { case 'off': {
if (!isSudo(message.author!)) return message.reply('You currently not in sudo mode.'); if (!isSudo(message.author!)) return message.reply('You currently not in sudo mode.');
sudoOverrides[message.author_id] = null; sudoOverrides[message.authorId!] = null;
let msg = `# %emoji% Sudo mode disabled.`; let msg = `# %emoji% Sudo mode disabled.`;
const sentMsg = await message.reply(msg.replace('%emoji%', ':unlock:'), false); const sentMsg = await message.reply(msg.replace('%emoji%', ':unlock:'), false);
@ -138,7 +137,7 @@ export default {
const target = await parseUserOrId(args.shift() || ''); const target = await parseUserOrId(args.shift() || '');
if (!target) return message.reply('Specified user could not be found.'); if (!target) return message.reply('Specified user could not be found.');
const res = await dbs.USERS.findOne({ id: target._id }); const res = await dbs.USERS.findOne({ id: target.id });
if (!res) await message.reply(`Nothing stored about this user.`); if (!res) await message.reply(`Nothing stored about this user.`);
else await message.reply(`\`\`\`json\n${JSON.stringify(res, null, 4)}\n\`\`\``); else await message.reply(`\`\`\`json\n${JSON.stringify(res, null, 4)}\n\`\`\``);
@ -149,12 +148,12 @@ export default {
case 'blacklist': { case 'blacklist': {
const target = await parseUserOrId(args.shift() || ''); const target = await parseUserOrId(args.shift() || '');
if (!target) return message.reply('Specified user could not be found.'); if (!target) return message.reply('Specified user could not be found.');
if (target._id == message.author_id) return message.reply(`no`); if (target.id == message.authorId) return message.reply(`no`);
await dbs.USERS.update({ await dbs.USERS.update({
id: target._id, id: target.id,
}, { }, {
$setOnInsert: { id: target._id }, $setOnInsert: { id: target.id },
$set: { globalBlacklist: true } $set: { globalBlacklist: true }
}, { upsert: true }); }, { upsert: true });
@ -167,23 +166,23 @@ export default {
const mutuals = getMutualServers(target); const mutuals = getMutualServers(target);
for (const server of mutuals) { for (const server of mutuals) {
if (server.havePermission('BanMembers')) { if (server.havePermission('BanMembers')) {
const config = await dbs.SERVERS.findOne({ id: server._id }); const config = await dbs.SERVERS.findOne({ id: server.id });
if (config?.allowBlacklistedUsers) continue; if (config?.allowBlacklistedUsers) continue;
try { try {
await server.banUser(target._id, { await server.banUser(target.id, {
reason: BLACKLIST_BAN_REASON, reason: BLACKLIST_BAN_REASON,
}); });
bannedServers++; bannedServers++;
if (server.system_messages?.user_banned) { if (server.systemMessages?.user_banned) {
const channel = server.channels.find(c => c!._id == server.system_messages!.user_banned); const channel = server.channels.find(c => c!.id == server.systemMessages!.user_banned);
if (channel && channel.havePermission('SendMessage')) { if (channel && channel.havePermission('SendMessage')) {
await channel.sendMessage(BLACKLIST_MESSAGE(target.username)); await channel.sendMessage(BLACKLIST_MESSAGE(target.username));
} }
} }
} catch(e) { } catch(e) {
console.error(`Failed to ban in ${server._id}: ${e}`); console.error(`Failed to ban in ${server.id}: ${e}`);
} }
} }
} }
@ -205,9 +204,9 @@ export default {
if (!target) return message.reply('Specified user could not be found.'); if (!target) return message.reply('Specified user could not be found.');
await dbs.USERS.update({ await dbs.USERS.update({
id: target._id, id: target.id,
}, { }, {
$setOnInsert: { id: target._id }, $setOnInsert: { id: target.id },
$set: { globalBlacklist: false } $set: { globalBlacklist: false }
}, { upsert: true }); }, { upsert: true });
@ -221,9 +220,9 @@ export default {
if (!target) return message.reply('Specified user could not be found.'); if (!target) return message.reply('Specified user could not be found.');
await dbs.USERS.update({ await dbs.USERS.update({
id: target._id, id: target.id,
}, { }, {
$setOnInsert: { id: target._id }, $setOnInsert: { id: target.id },
$set: { blacklistReason: args.join(' ') || undefined } $set: { blacklistReason: args.join(' ') || undefined }
}, { upsert: true }); }, { upsert: true });
@ -235,12 +234,12 @@ export default {
case 'ignore': { case 'ignore': {
const target = await parseUserOrId(args.shift() || ''); const target = await parseUserOrId(args.shift() || '');
if (!target) return message.reply('Specified user could not be found.'); if (!target) return message.reply('Specified user could not be found.');
if (target._id == message.author_id) return message.reply(`no`); if (target.id == message.authorId) return message.reply(`no`);
await dbs.USERS.update( await dbs.USERS.update(
{ id: target._id }, { id: target.id },
{ {
$setOnInsert: { id: target._id }, $setOnInsert: { id: target.id },
$set: { ignore: true }, $set: { ignore: true },
}, },
{ upsert: true } { upsert: true }
@ -254,12 +253,12 @@ export default {
case 'unignore': { case 'unignore': {
const target = await parseUserOrId(args.shift() || ''); const target = await parseUserOrId(args.shift() || '');
if (!target) return message.reply('Specified user could not be found.'); if (!target) return message.reply('Specified user could not be found.');
if (target._id == message.author_id) return message.reply(`no`); if (target.id == message.authorId) return message.reply(`no`);
await dbs.USERS.update( await dbs.USERS.update(
{ id: target._id }, { id: target.id },
{ {
$setOnInsert: { id: target._id }, $setOnInsert: { id: target.id },
$set: { ignore: false }, $set: { ignore: false },
}, },
{ upsert: true } { upsert: true }

View file

@ -1,7 +1,7 @@
import SimpleCommand from "../../../struct/commands/SimpleCommand"; import SimpleCommand from "../../../struct/commands/SimpleCommand";
import { hasPerm, parseUser } from "../../util"; import { parseUser } from "../../util";
import { client, dbs } from "../../.."; import { client, dbs } from "../../..";
import { User } from "@janderedev/revolt.js/dist/maps/Users"; import { User } from "revolt.js";
import MessageCommandContext from "../../../struct/MessageCommandContext"; import MessageCommandContext from "../../../struct/MessageCommandContext";
import CommandCategory from "../../../struct/commands/CommandCategory"; import CommandCategory from "../../../struct/commands/CommandCategory";
@ -14,10 +14,10 @@ export default {
syntax: SYNTAX, syntax: SYNTAX,
category: CommandCategory.Config, category: CommandCategory.Config,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
if (!hasPerm(message.member!, 'ManageServer')) if (!message.member?.hasPermission(message.member.server!, 'ManageServer'))
return message.reply('You need **ManageServer** permission to use this command.'); return message.reply('You need **ManageServer** permission to use this command.');
let config = await dbs.SERVERS.findOne({ id: message.serverContext._id }); let config = await dbs.SERVERS.findOne({ id: message.serverContext.id });
let admins = config?.botManagers ?? []; let admins = config?.botManagers ?? [];
let user: User|null; let user: User|null;
@ -28,12 +28,12 @@ export default {
user = await parseUser(args[1]); user = await parseUser(args[1]);
if (!user) return message.reply('I can\'t find that user.'); if (!user) return message.reply('I can\'t find that user.');
if (admins.indexOf(user._id) > -1) return message.reply('This user is already added as bot admin.'); if (admins.indexOf(user.id) > -1) return message.reply('This user is already added as bot admin.');
admins.push(user._id); admins.push(user.id);
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { botManagers: admins } }); await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { botManagers: admins } });
message.reply(`✅ Added [@${user.username}](/@${user._id}) to bot admins.`); message.reply(`✅ Added [@${user.username}](/@${user.id}) to bot admins.`);
break; break;
case 'remove': case 'remove':
case 'delete': case 'delete':
@ -43,12 +43,12 @@ export default {
user = await parseUser(args[1]); user = await parseUser(args[1]);
if (!user) return message.reply('I can\'t find that user.'); if (!user) return message.reply('I can\'t find that user.');
if (admins.indexOf(user._id) == -1) return message.reply('This user is not added as bot admin.'); if (admins.indexOf(user.id) == -1) return message.reply('This user is not added as bot admin.');
admins = admins.filter(a => a != user?._id); admins = admins.filter(a => a != user?.id);
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { botManagers: admins } }); await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { botManagers: admins } });
message.reply(`✅ Removed [@${user.username}](/@${user._id}) from bot admins.`); message.reply(`✅ Removed [@${user.username}](/@${user.id}) from bot admins.`);
break; break;
case 'list': case 'list':
case 'ls': case 'ls':

View file

@ -7,7 +7,7 @@ import SimpleCommand from "../../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../../struct/MessageCommandContext"; import MessageCommandContext from "../../../struct/MessageCommandContext";
import { checkMessageForFilteredWords } from "../../modules/antispam"; import { checkMessageForFilteredWords } from "../../modules/antispam";
import { DEFAULT_PREFIX } from "../../modules/command_handler"; import { DEFAULT_PREFIX } from "../../modules/command_handler";
import { embed, EmbedColor, getAutumnURL, getDmChannel, isBotManager, NO_MANAGER_MSG, sanitizeMessageContent } from "../../util"; import { embed, EmbedColor, getDmChannel, isBotManager, NO_MANAGER_MSG, sanitizeMessageContent } from "../../util";
const WORDLIST_DEFAULT_MESSAGE = '<@{{user_id}}>, the message you sent contained a blocked word.'; const WORDLIST_DEFAULT_MESSAGE = '<@{{user_id}}>, the message you sent contained a blocked word.';
@ -28,10 +28,10 @@ export default {
return message.reply('Your server is currently listed in server discovery. As part of Revolt\'s [Discover Guidelines](<https://support.revolt.chat/kb/safety/discover-guidelines>), all servers on Discover are enrolled to AutoMod\'s antispam features.'); return message.reply('Your server is currently listed in server discovery. As part of Revolt\'s [Discover Guidelines](<https://support.revolt.chat/kb/safety/discover-guidelines>), all servers on Discover are enrolled to AutoMod\'s antispam features.');
} }
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { allowBlacklistedUsers: true } }); await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { allowBlacklistedUsers: true } });
await message.reply('Globally blacklisted users will no longer get banned in this server. Previously banned users will need to be unbanned manually.'); await message.reply('Globally blacklisted users will no longer get banned in this server. Previously banned users will need to be unbanned manually.');
} else if (args[0] == 'no') { } else if (args[0] == 'no') {
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { allowBlacklistedUsers: false } }); await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { allowBlacklistedUsers: false } });
await message.reply('Globally blacklisted users will now get banned in this server.'); await message.reply('Globally blacklisted users will now get banned in this server.');
} else { } else {
await message.reply(`Please specify either 'yes' or 'no' to toggle this setting.`); await message.reply(`Please specify either 'yes' or 'no' to toggle this setting.`);
@ -41,7 +41,7 @@ export default {
case 'spam_detection': { case 'spam_detection': {
if (args[0] == 'on') { if (args[0] == 'on') {
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { antispamEnabled: true } }); await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { antispamEnabled: true } });
await message.reply('Spam detection is now enabled in this server.\nIf a user is wrongfully kicked ' await message.reply('Spam detection is now enabled in this server.\nIf a user is wrongfully kicked '
+ 'or banned, please report it here: https://rvlt.gg/jan\n\n' + 'or banned, please report it here: https://rvlt.gg/jan\n\n'
+ 'Please make sure to grant AutoMod permission to **Kick**, **Ban** and **Manage Messages**!'); + 'Please make sure to grant AutoMod permission to **Kick**, **Ban** and **Manage Messages**!');
@ -50,11 +50,11 @@ export default {
return message.reply('Your server is currently listed in server discovery. As part of Revolt\'s [Discover Guidelines](<https://support.revolt.chat/kb/safety/discover-guidelines>), all servers on Discover are enrolled to AutoMod\'s antispam features.'); return message.reply('Your server is currently listed in server discovery. As part of Revolt\'s [Discover Guidelines](<https://support.revolt.chat/kb/safety/discover-guidelines>), all servers on Discover are enrolled to AutoMod\'s antispam features.');
} }
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { antispamEnabled: false } }); await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { antispamEnabled: false } });
await message.reply('Spam detection is now disabled in this server.'); await message.reply('Spam detection is now disabled in this server.');
} else { } else {
const cfg = await dbs.SERVERS.findOne({ id: message.serverContext._id }); const cfg = await dbs.SERVERS.findOne({ id: message.serverContext.id });
await message.reply(`Spam detection is currently **${cfg?.antispamEnabled ? 'enabled' : 'disabled'}**. ` await message.reply(`Spam detection is currently **${cfg?.antispamEnabled ? 'enabled' : 'disabled'}**. `
+ `Please specify either 'on' or 'off' to toggle this setting.`); + `Please specify either 'on' or 'off' to toggle this setting.`);
} }
@ -80,48 +80,48 @@ export default {
const channel = client.channels.get(channelInput); const channel = client.channels.get(channelInput);
if (!channel) return message.reply('I can\'t find that channel.'); if (!channel) return message.reply('I can\'t find that channel.');
if (channel.server_id != message.channel?.server_id) return message.reply('That channel is not part of this server!'); if (channel.serverId != message.channel?.serverId) return message.reply('That channel is not part of this server!');
if (!channel.havePermission('SendMessage')) return message.reply('I don\'t have permission to **send messages** in that channel.'); if (!channel.havePermission('SendMessage')) return message.reply('I don\'t have permission to **send messages** in that channel.');
if (!channel.havePermission('SendEmbeds')) return message.reply('I don\'t have permission to **send embeds** in that channel.'); if (!channel.havePermission('SendEmbeds')) return message.reply('I don\'t have permission to **send embeds** in that channel.');
switch(args[0]?.toLowerCase()) { switch(args[0]?.toLowerCase()) {
case 'messageupdate': { case 'messageupdate': {
await dbs.SERVERS.update( await dbs.SERVERS.update(
{ id: message.channel!.server_id! }, { id: message.channel!.serverId! },
{ {
$set: { $set: {
'logs.messageUpdate.revolt': { 'logs.messageUpdate.revolt': {
channel: channel._id, channel: channel.id,
type: 'EMBED', type: 'EMBED',
}, },
}, },
$setOnInsert: { $setOnInsert: {
id: message.channel!.server_id!, id: message.channel!.serverId!,
} }
}, },
{ upsert: true }, { upsert: true },
); );
await message.reply(`Bound message update logs to <#${channel._id}>!`); await message.reply(`Bound message update logs to <#${channel.id}>!`);
break; break;
} }
case 'modaction': { case 'modaction': {
await dbs.SERVERS.update( await dbs.SERVERS.update(
{ id: message.channel!.server_id! }, { id: message.channel!.serverId! },
{ {
$set: { $set: {
'logs.modAction.revolt': { 'logs.modAction.revolt': {
channel: channel._id, channel: channel.id,
type: 'EMBED', type: 'EMBED',
}, },
}, },
$setOnInsert: { $setOnInsert: {
id: message.channel!.server_id!, id: message.channel!.serverId!,
} }
}, },
{ upsert: true }, { upsert: true },
); );
await message.reply(`Bound moderation logs to <#${channel._id}>!`); await message.reply(`Bound moderation logs to <#${channel.id}>!`);
break; break;
} }
@ -133,11 +133,11 @@ export default {
} }
case 'filter': { case 'filter': {
const config = await dbs.SERVERS.findOne({ id: message.channel!.server_id! }); const config = await dbs.SERVERS.findOne({ id: message.channel!.serverId! });
switch(args.shift()?.toLowerCase()) { switch(args.shift()?.toLowerCase()) {
case 'enable': { case 'enable': {
await dbs.SERVERS.update( await dbs.SERVERS.update(
{ id: message.channel!.server_id! }, { id: message.channel!.serverId! },
{ $set: { wordlistEnabled: true } }, { $set: { wordlistEnabled: true } },
{ upsert: true }, { upsert: true },
); );
@ -152,7 +152,7 @@ export default {
} }
case 'disable': { case 'disable': {
await dbs.SERVERS.update( await dbs.SERVERS.update(
{ id: message.channel!.server_id! }, { id: message.channel!.serverId! },
{ $set: { wordlistEnabled: false } }, { $set: { wordlistEnabled: false } },
{ upsert: true }, { upsert: true },
); );
@ -172,7 +172,7 @@ export default {
if (config?.wordlist?.find(w => w.word == word)) return await message.reply('That word is already on the list!'); if (config?.wordlist?.find(w => w.word == word)) return await message.reply('That word is already on the list!');
await dbs.SERVERS.update( await dbs.SERVERS.update(
{ id: message.channel!.server_id! }, { id: message.channel!.serverId! },
{ $push: { wordlist: { strictness, word } } }, { $push: { wordlist: { strictness, word } } },
{ upsert: true }, { upsert: true },
); );
@ -187,7 +187,7 @@ export default {
if (!config?.wordlist?.find(w => w.word == word)) return await message.reply('That word is not on the list.'); if (!config?.wordlist?.find(w => w.word == word)) return await message.reply('That word is not on the list.');
await dbs.SERVERS.update( await dbs.SERVERS.update(
{ id: message.channel!.server_id! }, { id: message.channel!.serverId! },
{ $pull: { wordlist: { word } } }, { $pull: { wordlist: { word } } },
{ upsert: true }, { upsert: true },
); );
@ -199,15 +199,15 @@ export default {
case 'show': { case 'show': {
const formData = new FormData(); const formData = new FormData();
formData.append( formData.append(
`wordlist_${message.channel?.server_id}`, `wordlist_${message.channel?.serverId}`,
config?.wordlist?.map(w => `${w.strictness}\t${w.word}`).join('\n') ?? '', config?.wordlist?.map(w => `${w.strictness}\t${w.word}`).join('\n') ?? '',
`wordlist_${message.channel?.server_id}.txt` `wordlist_${message.channel?.serverId}.txt`
); );
try { try {
const channel = await getDmChannel(message.author_id); const channel = await getDmChannel(message.authorId!);
const res = await axios.post( const res = await axios.post(
`${await getAutumnURL()}/attachments`, `${client.configuration?.features.autumn.url}/attachments`,
formData, formData,
{ headers: formData.getHeaders(), responseType: 'json' } { headers: formData.getHeaders(), responseType: 'json' }
); );
@ -244,7 +244,7 @@ export default {
} }
await dbs.SERVERS.update( await dbs.SERVERS.update(
{ id: message.channel!.server_id! }, { id: message.channel!.serverId! },
{ $set: { wordlistAction: { action: config?.wordlistAction?.action ?? 'LOG', message: msg } } }, { $set: { wordlistAction: { action: config?.wordlistAction?.action ?? 'LOG', message: msg } } },
{ upsert: true }, { upsert: true },
); );
@ -281,7 +281,7 @@ export default {
} }
await dbs.SERVERS.update( await dbs.SERVERS.update(
{ id: message.channel!.server_id! }, { id: message.channel!.serverId! },
{ $set: { wordlistAction: { { $set: { wordlistAction: {
action: action as any, action: action as any,
message: config?.wordlistAction?.message ?? WORDLIST_DEFAULT_MESSAGE message: config?.wordlistAction?.message ?? WORDLIST_DEFAULT_MESSAGE

View file

@ -1,4 +1,4 @@
import { Message } from "@janderedev/revolt.js"; import { Message } from "revolt.js";
import { ulid } from "ulid"; import { ulid } from "ulid";
import { SendableEmbed } from "revolt-api"; import { SendableEmbed } from "revolt-api";
import { CONFIG_KEYS } from "automod/dist/misc/bridge_config_keys"; import { CONFIG_KEYS } from "automod/dist/misc/bridge_config_keys";
@ -30,20 +30,20 @@ export default {
return message.reply(NO_MANAGER_MSG); return message.reply(NO_MANAGER_MSG);
const count = await dbs.BRIDGE_CONFIG.count({ const count = await dbs.BRIDGE_CONFIG.count({
revolt: message.channel_id, revolt: message.channelId,
}); });
if (count) if (count)
return message.reply(`This channel is already bridged.`); return message.reply(`This channel is already bridged.`);
// Invalidate previous bridge request // Invalidate previous bridge request
await dbs.BRIDGE_REQUESTS.remove({ await dbs.BRIDGE_REQUESTS.remove({
revolt: message.channel_id, revolt: message.channelId,
}); });
const reqId = ulid(); const reqId = ulid();
await dbs.BRIDGE_REQUESTS.insert({ await dbs.BRIDGE_REQUESTS.insert({
id: reqId, id: reqId,
revolt: message.channel_id, revolt: message.channelId,
expires: Date.now() + 1000 * 60 * 15, expires: Date.now() + 1000 * 60 * 15,
}); });
@ -74,7 +74,7 @@ export default {
return message.reply(NO_MANAGER_MSG); return message.reply(NO_MANAGER_MSG);
const res = await dbs.BRIDGE_CONFIG.remove({ const res = await dbs.BRIDGE_CONFIG.remove({
revolt: message.channel_id, revolt: message.channelId,
}); });
if (res.deletedCount) await message.reply(`Channel unlinked!`); if (res.deletedCount) await message.reply(`Channel unlinked!`);
else else
@ -86,7 +86,7 @@ export default {
return message.reply(NO_MANAGER_MSG); return message.reply(NO_MANAGER_MSG);
const query = { const query = {
revolt: { $in: message.channel?.server?.channel_ids || [] }, revolt: { $in: Array.from(message.channel?.server?.channelIds.values() ?? []) },
}; };
if (args[1] == "CONFIRM") { if (args[1] == "CONFIRM") {
const res = await dbs.BRIDGE_CONFIG.remove(query); const res = await dbs.BRIDGE_CONFIG.remove(query);
@ -119,7 +119,7 @@ export default {
return message.reply(NO_MANAGER_MSG); return message.reply(NO_MANAGER_MSG);
const links = await dbs.BRIDGE_CONFIG.find({ const links = await dbs.BRIDGE_CONFIG.find({
revolt: { $in: message.channel?.server?.channel_ids || [] }, revolt: { $in: Array.from(message.channel?.server?.channelIds.values() ?? []) },
}); });
await message.reply({ await message.reply({
@ -142,14 +142,14 @@ export default {
} }
case "info": { case "info": {
try { try {
if (!message.reply_ids) { if (!message.replyIds) {
return await message.reply( return await message.reply(
"Please run this command again while replying to a message." "Please run this command again while replying to a message."
); );
} }
if ( if (
message.reply_ids.length > 1 && message.replyIds.length > 1 &&
!(await isModerator(message, false)) !(await isModerator(message, false))
) { ) {
return await message.reply( return await message.reply(
@ -159,7 +159,7 @@ export default {
const messages = ( const messages = (
await Promise.allSettled( await Promise.allSettled(
message.reply_ids?.map((m) => message.replyIds.map((m) =>
message.channel!.fetchMessage(m) message.channel!.fetchMessage(m)
) || [] ) || []
) )
@ -179,7 +179,7 @@ export default {
messages.map(async (msg) => { messages.map(async (msg) => {
const bridgeData = const bridgeData =
await dbs.BRIDGED_MESSAGES.findOne({ await dbs.BRIDGED_MESSAGES.findOne({
"revolt.messageId": msg._id, "revolt.messageId": msg.id,
}); });
const embed: SendableEmbed = bridgeData const embed: SendableEmbed = bridgeData
@ -237,7 +237,7 @@ export default {
} }
case "status": { case "status": {
const link = await dbs.BRIDGE_CONFIG.findOne({ const link = await dbs.BRIDGE_CONFIG.findOne({
revolt: message.channel_id, revolt: message.channelId,
}); });
if (!link) if (!link)
@ -291,7 +291,7 @@ export default {
if (!newVal) { if (!newVal) {
const bridgeConfig = await dbs.BRIDGE_CONFIG.findOne({ const bridgeConfig = await dbs.BRIDGE_CONFIG.findOne({
revolt: message.channel_id, revolt: message.channelId,
}); });
return await message.reply({ return await message.reply({
embeds: [ embeds: [
@ -316,10 +316,10 @@ export default {
} }
await dbs.BRIDGE_CONFIG.update( await dbs.BRIDGE_CONFIG.update(
{ revolt: message.channel_id }, { revolt: message.channelId },
{ {
$set: { [`config.${configKey}`]: newVal == "true" }, $set: { [`config.${configKey}`]: newVal == "true" },
$setOnInsert: { revolt: message.channel_id }, $setOnInsert: { revolt: message.channelId },
}, },
{ upsert: true } { upsert: true }
); );

View file

@ -23,7 +23,7 @@ export default {
const login: FindOneResult<PendingLogin> = await dbs.PENDING_LOGINS.findOne({ const login: FindOneResult<PendingLogin> = await dbs.PENDING_LOGINS.findOne({
code, code,
user: message.author_id, user: message.authorId,
confirmed: false, confirmed: false,
exchanged: false, exchanged: false,
invalid: false, invalid: false,
@ -35,7 +35,7 @@ export default {
if (!login) return message.reply(`Unknown code. Make sure you're logged into the correct account.`); if (!login) return message.reply(`Unknown code. Make sure you're logged into the correct account.`);
if (login.requirePhishingConfirmation) { if (login.requirePhishingConfirmation) {
logger.info(`Showing phishing warning to ${message.author_id}`); logger.info(`Showing phishing warning to ${message.authorId}`);
await Promise.all([ await Promise.all([
message.reply( message.reply(
`# If someone told you to run this, stop!\n` + `# If someone told you to run this, stop!\n` +

View file

@ -20,8 +20,8 @@ export default {
if (code.toLowerCase() == 'all') { if (code.toLowerCase() == 'all') {
const [resA, resB] = await Promise.all([ const [resA, resB] = await Promise.all([
dbs.PENDING_LOGINS.update({ user: message.author_id, invalid: false }, { $set: { invalid: true } }), dbs.PENDING_LOGINS.update({ user: message.authorId, invalid: false }, { $set: { invalid: true } }),
dbs.SESSIONS.update({ user: message.author_id, invalid: false }, { $set: { invalid: true } }), dbs.SESSIONS.update({ user: message.authorId, invalid: false }, { $set: { invalid: true } }),
]); ]);
if (resA.nModified == 0 && resB.nModified == 0) return message.reply('There are no sessions to invalidate.'); if (resA.nModified == 0 && resB.nModified == 0) return message.reply('There are no sessions to invalidate.');
@ -30,7 +30,7 @@ export default {
} else { } else {
const loginAttempt = await dbs.PENDING_LOGINS.findOne({ const loginAttempt = await dbs.PENDING_LOGINS.findOne({
code: code.toUpperCase(), code: code.toUpperCase(),
user: message.author_id, user: message.authorId,
}); });
if (!loginAttempt || loginAttempt.invalid) { if (!loginAttempt || loginAttempt.invalid) {

View file

@ -1,7 +1,7 @@
import SimpleCommand from "../../../struct/commands/SimpleCommand"; import SimpleCommand from "../../../struct/commands/SimpleCommand";
import { isBotManager, NO_MANAGER_MSG, parseUser } from "../../util"; import { isBotManager, NO_MANAGER_MSG, parseUser } from "../../util";
import { client, dbs } from "../../.."; import { client, dbs } from "../../..";
import { User } from "@janderedev/revolt.js/dist/maps/Users"; import { User } from "revolt.js";
import MessageCommandContext from "../../../struct/MessageCommandContext"; import MessageCommandContext from "../../../struct/MessageCommandContext";
import CommandCategory from "../../../struct/commands/CommandCategory"; import CommandCategory from "../../../struct/commands/CommandCategory";
@ -18,7 +18,7 @@ export default {
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
if (!await isBotManager(message)) return message.reply(NO_MANAGER_MSG); if (!await isBotManager(message)) return message.reply(NO_MANAGER_MSG);
let config = await dbs.SERVERS.findOne({ id: message.serverContext._id }); let config = await dbs.SERVERS.findOne({ id: message.serverContext.id });
let mods = config?.moderators ?? []; let mods = config?.moderators ?? [];
let user: User|null; let user: User|null;
@ -29,12 +29,12 @@ export default {
user = await parseUser(args[1]); user = await parseUser(args[1]);
if (!user) return message.reply('I can\'t find that user.'); if (!user) return message.reply('I can\'t find that user.');
if (mods.indexOf(user._id) > -1) return message.reply('This user is already added as moderator.'); if (mods.indexOf(user.id) > -1) return message.reply('This user is already added as moderator.');
mods.push(user._id); mods.push(user.id);
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { moderators: mods } }); await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { moderators: mods } });
message.reply(`✅ Added [@${user.username}](/@${user._id}) to moderators.`); message.reply(`✅ Added [@${user.username}](/@${user.id}) to moderators.`);
break; break;
case 'remove': case 'remove':
case 'delete': case 'delete':
@ -44,12 +44,12 @@ export default {
user = await parseUser(args[1]); user = await parseUser(args[1]);
if (!user) return message.reply('I can\'t find that user.'); if (!user) return message.reply('I can\'t find that user.');
if (mods.indexOf(user._id) == -1) return message.reply('This user is not added as moderator.'); if (mods.indexOf(user.id) == -1) return message.reply('This user is not added as moderator.');
mods = mods.filter(a => a != user?._id); mods = mods.filter(a => a != user?.id);
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { moderators: mods } }); await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { moderators: mods } });
message.reply(`✅ Removed [@${user.username}](/@${user._id}) from moderators.`); message.reply(`✅ Removed [@${user.username}](/@${user.id}) from moderators.`);
break; break;
case 'list': case 'list':
case 'ls': case 'ls':

View file

@ -15,7 +15,7 @@ export default {
syntax: SYNTAX, syntax: SYNTAX,
category: CommandCategory.Config, category: CommandCategory.Config,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
let config = await dbs.SERVERS.findOne({ id: message.channel!.server_id! }); let config = await dbs.SERVERS.findOne({ id: message.channel!.serverId! });
switch(args[0]?.toLowerCase()) { switch(args[0]?.toLowerCase()) {
case 'set': case 'set':
@ -31,7 +31,7 @@ export default {
return message.reply(val); return message.reply(val);
} }
await dbs.SERVERS.update({ id: message.channel!.server_id! }, { $set: { 'prefix': newPrefix } }); await dbs.SERVERS.update({ id: message.channel!.serverId! }, { $set: { 'prefix': newPrefix } });
message.reply(`✅ Prefix has been changed from \`${oldPrefix}\` to \`${newPrefix}\`.\n${MENTION_TEXT}`); message.reply(`✅ Prefix has been changed from \`${oldPrefix}\` to \`${newPrefix}\`.\n${MENTION_TEXT}`);
break; break;
@ -45,7 +45,7 @@ export default {
if (!await isBotManager(message)) return message.reply(NO_MANAGER_MSG); if (!await isBotManager(message)) return message.reply(NO_MANAGER_MSG);
if (config?.prefix != null) { if (config?.prefix != null) {
await dbs.SERVERS.update({ id: message.channel!.server_id! }, { $set: { prefix: undefined } }); await dbs.SERVERS.update({ id: message.channel!.serverId! }, { $set: { prefix: undefined } });
} }
message.reply(`✅ Prefix has been reset to the default: \`${DEFAULT_PREFIX}\`.`); message.reply(`✅ Prefix has been reset to the default: \`${DEFAULT_PREFIX}\`.`);

View file

@ -1,4 +1,4 @@
import { User } from "@janderedev/revolt.js/dist/maps/Users"; import { User } from "revolt.js";
import { client, dbs } from "../../.."; import { client, dbs } from "../../..";
import CommandCategory from "../../../struct/commands/CommandCategory"; import CommandCategory from "../../../struct/commands/CommandCategory";
import SimpleCommand from "../../../struct/commands/SimpleCommand"; import SimpleCommand from "../../../struct/commands/SimpleCommand";
@ -15,8 +15,8 @@ export default {
syntax: SYNTAX, syntax: SYNTAX,
category: CommandCategory.Config, category: CommandCategory.Config,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
let config: ServerConfig|null = await dbs.SERVERS.findOne({ id: message.serverContext._id }) let config: ServerConfig|null = await dbs.SERVERS.findOne({ id: message.serverContext.id })
if (!config) config = { id: message.channel!.server_id! }; if (!config) config = { id: message.channel!.serverId! };
if (!config.whitelist) config.whitelist = { users: [], roles: [], managers: true } if (!config.whitelist) config.whitelist = { users: [], roles: [], managers: true }
if (!isBotManager(message)) return message.reply(NO_MANAGER_MSG); if (!isBotManager(message)) return message.reply(NO_MANAGER_MSG);
@ -37,18 +37,18 @@ export default {
return message.reply('That role is already whitelisted.'); return message.reply('That role is already whitelisted.');
config.whitelist!.roles = [role, ...(config.whitelist!.roles ?? [])]; config.whitelist!.roles = [role, ...(config.whitelist!.roles ?? [])];
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { whitelist: config.whitelist } }); await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { whitelist: config.whitelist } });
return message.reply(`Added role to whitelist!`); return message.reply(`Added role to whitelist!`);
} }
user = await parseUser(args[1]) user = await parseUser(args[1])
if (user == null) return message.reply('I can\'t find that user or role.'); if (user == null) return message.reply('I can\'t find that user or role.');
if (user.bot != null) return message.reply('Bots cannot be whitelisted.'); if (user.bot != null) return message.reply('Bots cannot be whitelisted.');
if (config.whitelist!.users?.includes(user._id)) if (config.whitelist!.users?.includes(user.id))
return message.reply('That user is already whitelisted.'); return message.reply('That user is already whitelisted.');
config.whitelist!.users = [user._id, ...(config.whitelist!.users ?? [])]; config.whitelist!.users = [user.id, ...(config.whitelist!.users ?? [])];
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { whitelist: config.whitelist } }); await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { whitelist: config.whitelist } });
return message.reply('Added user to whitelist!'); return message.reply('Added user to whitelist!');
break; break;
case 'rm': case 'rm':
@ -67,17 +67,17 @@ export default {
return message.reply('That role is not whitelisted.'); return message.reply('That role is not whitelisted.');
config.whitelist!.roles = config.whitelist!.roles.filter(r => r != role); config.whitelist!.roles = config.whitelist!.roles.filter(r => r != role);
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { whitelist: config.whitelist } }); await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { whitelist: config.whitelist } });
return message.reply(`Removed role from whitelist!`); return message.reply(`Removed role from whitelist!`);
} }
user = await parseUser(args[1]) user = await parseUser(args[1])
if (user == null) return message.reply('I can\'t find that user or role.'); if (user == null) return message.reply('I can\'t find that user or role.');
if (!config.whitelist!.users?.includes(user._id)) if (!config.whitelist!.users?.includes(user.id))
return message.reply('That user is not whitelisted.'); return message.reply('That user is not whitelisted.');
config.whitelist!.users = config.whitelist!.users.filter(u => u != user?._id); config.whitelist!.users = config.whitelist!.users.filter(u => u != user?.id);
await dbs.SERVERS.update({ id: message.serverContext._id }, { $set: { whitelist: config.whitelist } }); await dbs.SERVERS.update({ id: message.serverContext.id }, { $set: { whitelist: config.whitelist } });
return message.reply('Removed user from whitelist!'); return message.reply('Removed user from whitelist!');
break; break;
case 'l': case 'l':
@ -98,7 +98,7 @@ export default {
if (config.whitelist.roles?.length) { if (config.whitelist.roles?.length) {
config.whitelist.roles config.whitelist.roles
?.map(r => message.serverContext.roles?.[r]?.name || `Unknown role (${r})`) ?.map(r => message.serverContext.roles.get(r)?.name || `Unknown role (${r})`)
.forEach((r, index) => { .forEach((r, index) => {
if (index < 15) str += `* ${r}\n`; if (index < 15) str += `* ${r}\n`;
if (index == 15) str += `**${config!.whitelist!.roles!.length - 15} more role${config?.whitelist?.roles?.length == 16 ? '' : 's'}**\n`; if (index == 15) str += `**${config!.whitelist!.roles!.length - 15} more role${config?.whitelist?.roles?.length == 16 ? '' : 's'}**\n`;

View file

@ -31,11 +31,11 @@ export default {
); );
} else { } else {
await message.reply( await message.reply(
`Server ID: ${message.channel?.server_id || 'None'}\n` `Server ID: ${message.channel?.serverId || 'None'}\n`
+ `Server context: ${message.serverContext._id} ` + `Server context: ${message.serverContext.id} `
+ `(${message.serverContext._id == message.channel?.server_id ? 'This server' : message.serverContext.name})\n` + `(${message.serverContext.id == message.channel?.serverId ? 'This server' : message.serverContext.name})\n`
+ `Channel ID: ${message.channel_id}\n` + `Channel ID: ${message.channelId}\n`
+ `User ID: ${message.author_id}`, + `User ID: ${message.authorId}`,
false false
); );
} }

View file

@ -42,7 +42,7 @@ export default {
removeEmptyArgs: true, removeEmptyArgs: true,
category: CommandCategory.Misc, category: CommandCategory.Misc,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
const isBotOwner = ownerIDs.includes(message.author_id); const isBotOwner = ownerIDs.includes(message.authorId!);
const prefix = DEFAULT_PREFIX; // TODO: fetch prefix from server config const prefix = DEFAULT_PREFIX; // TODO: fetch prefix from server config
let searchInput = args.shift()?.toLowerCase(); let searchInput = args.shift()?.toLowerCase();
@ -50,7 +50,7 @@ export default {
let msg = `## AutoMod help\n` + let msg = `## AutoMod help\n` +
`Type **${prefix}help [category]** to view see all commands or **${prefix}help [command]** to learn more about a command.\n\n` `Type **${prefix}help [category]** to view see all commands or **${prefix}help [command]** to learn more about a command.\n\n`
+ `### [Open Server Settings]` + `### [Open Server Settings]`
+ `(<${process.env.WEB_UI_URL || 'https://automod.janderedev.xyz'}/dashboard/${message.channel?.server_id}>)\n\n`; + `(<${process.env.WEB_UI_URL || 'https://automod.janderedev.xyz'}/dashboard/${message.channel?.serverId}>)\n\n`;
let total = 0; let total = 0;

View file

@ -14,8 +14,8 @@ export default {
?.catch(console.error) ?.catch(console.error)
.then(msg => { .then(msg => {
if (msg) msg.edit({ content: `## Ping Pong!\n` if (msg) msg.edit({ content: `## Ping Pong!\n`
+ `WS: \`${client.websocket.ping ?? '--'}ms\`\n` + `WS: \`${client.events.ping() ?? '--'}ms\`\n`
+ `Msg: \`${Math.round(Date.now() - now) / 2}ms\`` }); + `Msg: \`${Math.round(Date.now() - now)}ms\`` });
}); });
} }
} as SimpleCommand; } as SimpleCommand;

View file

@ -1,9 +1,11 @@
import { Member } from "@janderedev/revolt.js/dist/maps/Members"; import { ServerMember } from "revolt.js";
import axios from "axios"; import axios from "axios";
import CommandCategory from "../../../struct/commands/CommandCategory"; import CommandCategory from "../../../struct/commands/CommandCategory";
import SimpleCommand from "../../../struct/commands/SimpleCommand"; import SimpleCommand from "../../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../../struct/MessageCommandContext"; import MessageCommandContext from "../../../struct/MessageCommandContext";
import { hasPerm, isModerator, NO_MANAGER_MSG, parseUser } from "../../util"; import { isModerator, NO_MANAGER_MSG, parseUser } from "../../util";
import AutomodClient from "../../../struct/AutomodClient";
import { client } from "../../..";
export default { export default {
name: 'avatar', name: 'avatar',
@ -23,13 +25,13 @@ export default {
|| args[0]?.toLowerCase() == 'clear') { || args[0]?.toLowerCase() == 'clear') {
// Clear server avatar // Clear server avatar
if (!message.member) return; if (!message.member) return;
if (!hasPerm(message.member, 'RemoveAvatars') if (!message.member.hasPermission(message.member.server!, 'RemoveAvatars')
&& !await isModerator(message)) return message.reply(NO_MANAGER_MSG); && !await isModerator(message)) return message.reply(NO_MANAGER_MSG);
if (!target.avatar) { if (!target.avatar) {
await message.reply(`\`@${targetUser.username}\` does not currently have an avatar set for this server.`); await message.reply(`\`@${targetUser.username}\` does not currently have an avatar set for this server.`);
} else { } else {
await clearAvatar(target); await target.edit({ remove: ['Avatar'] });
await message.reply(`\`@${targetUser.username}\`'s server avatar has been cleared.`); await message.reply(`\`@${targetUser.username}\`'s server avatar has been cleared.`);
} }
} else { } else {
@ -37,9 +39,9 @@ export default {
await message.reply( await message.reply(
`### \`@${targetUser.username}\`'s avatar\n` + `### \`@${targetUser.username}\`'s avatar\n` +
(targetUser.avatar ? `[\\[Global\\]](<${targetUser.generateAvatarURL()}>)` : '[No global avatar]') + (targetUser.avatar ? `[\\[Global\\]](<${targetUser.avatarURL}>)` : '[No global avatar]') +
' | ' + ' | ' +
(target.avatar ? `[\\[Server\\]](<${target.generateAvatarURL()}>)` : '[No server avatar]') (target.avatar ? `[\\[Server\\]](<${target.avatarURL}>)` : '[No server avatar]')
); );
} }
} catch(e) { } catch(e) {
@ -48,17 +50,3 @@ export default {
} }
} }
} as SimpleCommand; } as SimpleCommand;
async function clearAvatar(member: Member) {
await axios.patch(
`${member.client.apiURL}/servers/${member.server!._id}/members/${member._id.user}`,
{
remove: [ "Avatar" ],
},
{
headers: {
'x-bot-token': process.env['BOT_TOKEN']!
}
}
);
}

View file

@ -13,6 +13,7 @@ import {
getDmChannel, getDmChannel,
getMembers, getMembers,
isModerator, isModerator,
memberRanking,
NO_MANAGER_MSG, NO_MANAGER_MSG,
parseUserOrId, parseUserOrId,
sanitizeMessageContent, sanitizeMessageContent,
@ -23,7 +24,7 @@ import Day from "dayjs";
import RelativeTime from "dayjs/plugin/relativeTime"; import RelativeTime from "dayjs/plugin/relativeTime";
import CommandCategory from "../../../struct/commands/CommandCategory"; import CommandCategory from "../../../struct/commands/CommandCategory";
import { SendableEmbed } from "revolt-api"; import { SendableEmbed } from "revolt-api";
import { User } from "@janderedev/revolt.js"; import { User } from "revolt.js";
import logger from "../../logger"; import logger from "../../logger";
Day.extend(RelativeTime); Day.extend(RelativeTime);
@ -49,10 +50,10 @@ export default {
}); });
} }
const userInput = !message.reply_ids?.length const userInput = !message.replyIds?.length
? args.shift() || "" ? args.shift() || ""
: undefined; : undefined;
if (!userInput && !message.reply_ids?.length) if (!userInput && !message.replyIds?.length)
return message.reply({ return message.reply({
embeds: [ embeds: [
embed( embed(
@ -121,13 +122,13 @@ export default {
const embeds: SendableEmbed[] = []; const embeds: SendableEmbed[] = [];
const handledUsers: string[] = []; const handledUsers: string[] = [];
const targetUsers: User | { _id: string }[] = []; const targetUsers: User | { id: string }[] = [];
const targetInput = dedupeArray( const targetInput = dedupeArray(
message.reply_ids?.length message.replyIds?.length
? ( ? (
await Promise.allSettled( await Promise.allSettled(
message.reply_ids.map((msg) => message.replyIds.map((msg) =>
message.channel?.fetchMessage(msg) message.channel?.fetchMessage(msg)
) )
) )
@ -154,10 +155,10 @@ export default {
} }
// Silently ignore duplicates // Silently ignore duplicates
if (handledUsers.includes(user._id)) continue; if (handledUsers.includes(user.id)) continue;
handledUsers.push(user._id); handledUsers.push(user.id);
if (user._id == message.author_id) { if (user.id == message.authorId!) {
embeds.push( embeds.push(
embed( embed(
"I recommend against banning yourself :yeahokayyy:", "I recommend against banning yourself :yeahokayyy:",
@ -168,7 +169,7 @@ export default {
continue; continue;
} }
if (user._id == client.user!._id) { if (user.id == client.user!.id) {
embeds.push( embeds.push(
embed( embed(
"I'm not going to ban myself :flushee:", "I'm not going to ban myself :flushee:",
@ -194,21 +195,21 @@ export default {
} }
} }
if (message.reply_ids?.length && targetUsers.length) { if (message.replyIds?.length && targetUsers.length) {
let res = await yesNoMessage( let res = await yesNoMessage(
message.channel!, message.channel!,
message.author_id, message.authorId!,
`This will ban the author${targetUsers.length > 1 ? 's' : ''} ` `This will ban the author${targetUsers.length > 1 ? 's' : ''} `
+ `of the message${message.reply_ids.length > 1 ? 's' : ''} you replied to.\n` + `of the message${message.replyIds.length > 1 ? 's' : ''} you replied to.\n`
+ `The following user${targetUsers.length > 1 ? 's' : ''} will be affected: ` + `The following user${targetUsers.length > 1 ? 's' : ''} will be affected: `
+ `${targetUsers.map(u => `<@${u._id}>`).join(', ')}.\n` + `${targetUsers.map(u => `<@${u.id}>`).join(', ')}.\n`
+ `Are you sure?`, + `Are you sure?`,
'Confirm action' 'Confirm action'
); );
if (!res) return; if (!res) return;
} }
const members = getMembers(message.serverContext._id); const members = getMembers(message.serverContext.id);
for (const user of targetUsers) { for (const user of targetUsers) {
try { try {
@ -216,18 +217,18 @@ export default {
const infId = ulid(); const infId = ulid();
const infraction: Infraction = { const infraction: Infraction = {
_id: infId, _id: infId,
createdBy: message.author_id, createdBy: message.authorId!,
date: Date.now(), date: Date.now(),
reason: reason || "No reason provided", reason: reason || "No reason provided",
server: message.serverContext._id, server: message.serverContext.id,
type: InfractionType.Manual, type: InfractionType.Manual,
user: user._id, user: user.id,
actionType: "ban", actionType: "ban",
expires: Infinity, expires: Infinity,
}; };
const { userWarnCount } = await storeInfraction(infraction); const { userWarnCount } = await storeInfraction(infraction);
const member = members.find((m) => m._id.user == user._id); const member = members.find((m) => m.id.user == user.id);
if ( if (
member && member &&
@ -244,11 +245,11 @@ export default {
continue; continue;
} }
if (member && !member.bannable) { if (member && !memberRanking(member).bannable) {
embeds.push( embeds.push(
embed( embed(
`I don't have permission to ban \`${ `I don't have permission to ban \`${
member?.user?.username || user._id member?.user?.username || user.id
}\`.`, }\`.`,
null, null,
EmbedColor.SoftError EmbedColor.SoftError
@ -281,11 +282,11 @@ export default {
} }
} }
await message.serverContext.banUser(user._id, { await message.serverContext.banUser(user.id, {
reason: reason:
reason + reason +
` (by ${await fetchUsername(message.author_id)} ${ ` (by ${await fetchUsername(message.authorId!)} ${
message.author_id message.authorId
})`, })`,
}); });
@ -293,7 +294,7 @@ export default {
"ban", "ban",
message.serverContext, message.serverContext,
message.member!, message.member!,
user._id, user.id,
reason, reason,
infraction._id, infraction._id,
`Ban duration: **Permanent**` `Ban duration: **Permanent**`
@ -305,7 +306,7 @@ export default {
}`, }`,
icon_url: icon_url:
user instanceof User user instanceof User
? user.generateAvatarURL() ? user.avatarURL
: undefined, : undefined,
colour: EmbedColor.Success, colour: EmbedColor.Success,
description: description:
@ -314,8 +315,8 @@ export default {
? "**the first infraction**" ? "**the first infraction**"
: `infraction number **${userWarnCount}**` : `infraction number **${userWarnCount}**`
}` + }` +
` for ${await fetchUsername(user._id)}.\n` + ` for ${await fetchUsername(user.id)}.\n` +
`**User ID:** \`${user._id}\`\n` + `**User ID:** \`${user.id}\`\n` +
`**Infraction ID:** \`${infraction._id}\`\n` + `**Infraction ID:** \`${infraction._id}\`\n` +
`**Reason:** \`${infraction.reason}\``, `**Reason:** \`${infraction.reason}\``,
}); });
@ -325,14 +326,14 @@ export default {
const infId = ulid(); const infId = ulid();
const infraction: Infraction = { const infraction: Infraction = {
_id: infId, _id: infId,
createdBy: message.author_id, createdBy: message.authorId!,
date: Date.now(), date: Date.now(),
reason: reason:
(reason || "No reason provided") + (reason || "No reason provided") +
` (${durationStr})`, ` (${durationStr})`,
server: message.serverContext._id, server: message.serverContext.id,
type: InfractionType.Manual, type: InfractionType.Manual,
user: user._id, user: user.id,
actionType: "ban", actionType: "ban",
expires: banUntil, expires: banUntil,
}; };
@ -362,26 +363,26 @@ export default {
} }
} }
await message.serverContext.banUser(user._id, { await message.serverContext.banUser(user.id, {
reason: reason:
reason + reason +
` (by ${await fetchUsername(message.author_id)} ${ ` (by ${await fetchUsername(message.authorId!)} ${
message.author_id message.authorId
}) (${durationStr})`, }) (${durationStr})`,
}); });
await Promise.all([ await Promise.all([
storeTempBan({ storeTempBan({
id: infId, id: infId,
bannedUser: user._id, bannedUser: user.id,
server: message.serverContext._id, server: message.serverContext.id,
until: banUntil, until: banUntil,
}), }),
logModAction( logModAction(
"ban", "ban",
message.serverContext, message.serverContext,
message.member!, message.member!,
user._id, user.id,
reason, reason,
infraction._id, infraction._id,
`Ban duration: **${banDurationFancy}**` `Ban duration: **${banDurationFancy}**`
@ -392,7 +393,7 @@ export default {
title: `User temporarily banned`, title: `User temporarily banned`,
icon_url: icon_url:
user instanceof User user instanceof User
? user.generateAvatarURL() ? user.avatarURL
: undefined, : undefined,
colour: EmbedColor.Success, colour: EmbedColor.Success,
description: description:
@ -401,9 +402,9 @@ export default {
? "**the first infraction**" ? "**the first infraction**"
: `infraction number **${userWarnCount}**` : `infraction number **${userWarnCount}**`
}` + }` +
` for ${await fetchUsername(user._id)}.\n` + ` for ${await fetchUsername(user.id)}.\n` +
`**Ban duration:** ${banDurationFancy}\n` + `**Ban duration:** ${banDurationFancy}\n` +
`**User ID:** \`${user._id}\`\n` + `**User ID:** \`${user.id}\`\n` +
`**Infraction ID:** \`${infraction._id}\`\n` + `**Infraction ID:** \`${infraction._id}\`\n` +
`**Reason:** \`${infraction.reason}\``, `**Reason:** \`${infraction.reason}\``,
}); });
@ -413,8 +414,8 @@ export default {
embeds.push( embeds.push(
embed( embed(
`Failed to ban target \`${await fetchUsername( `Failed to ban target \`${await fetchUsername(
user._id, user.id,
user._id user.id
)}\`: ${e}`, )}\`: ${e}`,
"Failed to ban: An error has occurred", "Failed to ban: An error has occurred",
EmbedColor.Error EmbedColor.Error

View file

@ -1,4 +1,4 @@
import { User } from "@janderedev/revolt.js"; import { User } from "revolt.js";
import { SendableEmbed } from "revolt-api"; import { SendableEmbed } from "revolt-api";
import { ulid } from "ulid"; import { ulid } from "ulid";
import { client } from "../../../"; import { client } from "../../../";
@ -39,10 +39,10 @@ export default {
); );
} }
const userInput = !message.reply_ids?.length const userInput = !message.replyIds?.length
? args.shift() || "" ? args.shift() || ""
: undefined; : undefined;
if (!userInput && !message.reply_ids?.length) if (!userInput && !message.replyIds?.length)
return message.reply({ return message.reply({
embeds: [ embeds: [
embed( embed(
@ -72,19 +72,19 @@ export default {
const embeds: SendableEmbed[] = []; const embeds: SendableEmbed[] = [];
const handledUsers: string[] = []; const handledUsers: string[] = [];
const targetUsers: User | { _id: string }[] = []; const targetUsers: User | { id: string }[] = [];
const targetInput = dedupeArray( const targetInput = dedupeArray(
message.reply_ids?.length message.replyIds?.length
? ( ? (
await Promise.allSettled( await Promise.allSettled(
message.reply_ids.map((msg) => message.replyIds.map((msg) =>
message.channel?.fetchMessage(msg) message.channel?.fetchMessage(msg)
) )
) )
) )
.filter((m) => m.status == "fulfilled") .filter((m) => m.status == "fulfilled")
.map((m) => (m as any).value.author_id) .map((m) => (m as any).value.authorId)
: userInput!.split(",") : userInput!.split(",")
); );
@ -105,10 +105,10 @@ export default {
} }
// Silently ignore duplicates // Silently ignore duplicates
if (handledUsers.includes(user._id)) continue; if (handledUsers.includes(user.id)) continue;
handledUsers.push(user._id); handledUsers.push(user.id);
if (user._id == message.author_id) { if (user.id == message.authorId) {
embeds.push( embeds.push(
embed( embed(
"You might want to avoid kicking yourself...", "You might want to avoid kicking yourself...",
@ -119,7 +119,7 @@ export default {
continue; continue;
} }
if (user._id == client.user!._id) { if (user.id == client.user!.id) {
embeds.push( embeds.push(
embed( embed(
"I won't allow you to get rid of me this easily :trol:", "I won't allow you to get rid of me this easily :trol:",
@ -145,30 +145,30 @@ export default {
} }
} }
if (message.reply_ids?.length && targetUsers.length) { if (message.replyIds?.length && targetUsers.length) {
let res = await yesNoMessage( let res = await yesNoMessage(
message.channel!, message.channel!,
message.author_id, message.authorId!,
`This will kick the author${targetUsers.length > 1 ? 's' : ''} ` `This will kick the author${targetUsers.length > 1 ? 's' : ''} `
+ `of the message${message.reply_ids.length > 1 ? 's' : ''} you replied to.\n` + `of the message${message.replyIds.length > 1 ? 's' : ''} you replied to.\n`
+ `The following user${targetUsers.length > 1 ? 's' : ''} will be affected: ` + `The following user${targetUsers.length > 1 ? 's' : ''} will be affected: `
+ `${targetUsers.map(u => `<@${u._id}>`).join(', ')}.\n` + `${targetUsers.map(u => `<@${u.id}>`).join(', ')}.\n`
+ `Are you sure?`, + `Are you sure?`,
'Confirm action' 'Confirm action'
); );
if (!res) return; if (!res) return;
} }
const members = getMembers(message.serverContext._id); const members = getMembers(message.serverContext.id);
for (const user of targetUsers) { for (const user of targetUsers) {
try { try {
const member = members.find((m) => m._id.user == user._id); const member = members.find((m) => m.id.user == user.id);
if (!member) { if (!member) {
embeds.push( embeds.push(
embed( embed(
`\`${await fetchUsername( `\`${await fetchUsername(
user._id user.id
)}\` is not a member of this server.` )}\` is not a member of this server.`
) )
); );
@ -178,12 +178,12 @@ export default {
let infId = ulid(); let infId = ulid();
let infraction: Infraction = { let infraction: Infraction = {
_id: infId, _id: infId,
createdBy: message.author_id, createdBy: message.authorId!,
date: Date.now(), date: Date.now(),
reason: reason || "No reason provided", reason: reason || "No reason provided",
server: message.serverContext._id, server: message.serverContext.id,
type: InfractionType.Manual, type: InfractionType.Manual,
user: user._id, user: user.id,
actionType: "kick", actionType: "kick",
}; };
@ -214,7 +214,7 @@ export default {
"kick", "kick",
message.serverContext, message.serverContext,
message.member!, message.member!,
user._id, user.id,
reason, reason,
infraction._id infraction._id
), ),
@ -225,7 +225,7 @@ export default {
title: `User kicked`, title: `User kicked`,
icon_url: icon_url:
user instanceof User user instanceof User
? user.generateAvatarURL() ? user.avatarURL
: undefined, : undefined,
colour: EmbedColor.Success, colour: EmbedColor.Success,
description: description:
@ -234,8 +234,8 @@ export default {
? "**the first infraction**" ? "**the first infraction**"
: `infraction number **${userWarnCount}**` : `infraction number **${userWarnCount}**`
}` + }` +
` for ${await fetchUsername(user._id)}.\n` + ` for ${await fetchUsername(user.id)}.\n` +
`**User ID:** \`${user._id}\`\n` + `**User ID:** \`${user.id}\`\n` +
`**Infraction ID:** \`${infraction._id}\`\n` + `**Infraction ID:** \`${infraction._id}\`\n` +
`**Reason:** \`${infraction.reason}\``, `**Reason:** \`${infraction.reason}\``,
}); });
@ -243,7 +243,7 @@ export default {
embeds.push( embeds.push(
embed( embed(
`Failed to kick user ${await fetchUsername( `Failed to kick user ${await fetchUsername(
user._id user.id
)}: ${e}`, )}: ${e}`,
"Failed to kick user", "Failed to kick user",
EmbedColor.Error EmbedColor.Error

View file

@ -1,9 +1,10 @@
import { Member } from "@janderedev/revolt.js/dist/maps/Members"; import { ServerMember } from "revolt.js";
import axios from "axios"; import axios from "axios";
import CommandCategory from "../../../struct/commands/CommandCategory"; import CommandCategory from "../../../struct/commands/CommandCategory";
import SimpleCommand from "../../../struct/commands/SimpleCommand"; import SimpleCommand from "../../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../../struct/MessageCommandContext"; import MessageCommandContext from "../../../struct/MessageCommandContext";
import { hasPerm, isModerator, NO_MANAGER_MSG, parseUser } from "../../util"; import { isModerator, NO_MANAGER_MSG, parseUser } from "../../util";
import { client } from "../../..";
export default { export default {
name: 'nick', name: 'nick',
@ -13,7 +14,7 @@ export default {
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
try { try {
if (!message.member) return; if (!message.member) return;
if (!hasPerm(message.member, 'ManageNicknames') if (!message.member.hasPermission(message.member.server!, 'ManageNicknames')
&& !await isModerator(message)) return message.reply(NO_MANAGER_MSG); && !await isModerator(message)) return message.reply(NO_MANAGER_MSG);
const targetStr = args.shift(); const targetStr = args.shift();
@ -42,9 +43,9 @@ export default {
} }
} as SimpleCommand; } as SimpleCommand;
async function setNick(member: Member, newName: string|null) { async function setNick(member: ServerMember, newName: string|null) {
await axios.patch( await axios.patch(
`${member.client.apiURL}/servers/${member.server!._id}/members/${member._id.user}`, `${client.options.baseURL}/servers/${member.server!.id}/members/${member.id.user}`,
{ {
nickname: newName || undefined, nickname: newName || undefined,
remove: !newName ? [ "Nickname" ] : undefined, remove: !newName ? [ "Nickname" ] : undefined,

View file

@ -1,5 +1,5 @@
import SimpleCommand from "../../../struct/commands/SimpleCommand"; import SimpleCommand from "../../../struct/commands/SimpleCommand";
import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { Message } from "revolt.js";
import { decodeTime } from 'ulid'; import { decodeTime } from 'ulid';
import { isModerator, parseUserOrId } from "../../util"; import { isModerator, parseUserOrId } from "../../util";
import MessageCommandContext from "../../../struct/MessageCommandContext"; import MessageCommandContext from "../../../struct/MessageCommandContext";
@ -31,7 +31,7 @@ export default {
messages = await message.channel!.fetchMessages({ messages = await message.channel!.fetchMessages({
limit: amount, limit: amount,
before: message._id, before: message.id,
}); });
} }
// delete messages between [id] and [id] // delete messages between [id] and [id]
@ -49,7 +49,7 @@ export default {
]); ]);
// Make sure the msg1 and msg2 are in the correct order // Make sure the msg1 and msg2 are in the correct order
if (decodeTime(msg1._id) < decodeTime(msg2._id)) { if (decodeTime(msg1.id) < decodeTime(msg2.id)) {
[msg1, msg2] = [msg2, msg1]; [msg1, msg2] = [msg2, msg1];
} }
@ -60,17 +60,17 @@ export default {
sort: "Latest", sort: "Latest",
}); });
if (!messages.find((m) => m._id == msg1._id)) if (!messages.find((m) => m.id == msg1.id))
messages = [msg1, ...messages]; messages = [msg1, ...messages];
if (!messages.find((m) => m._id == msg2._id)) if (!messages.find((m) => m.id == msg2.id))
messages = [...messages, msg2]; messages = [...messages, msg2];
// Discard messages that are not in the selected range, // Discard messages that are not in the selected range,
// because Revolt returns more messages than expected for some reason // because Revolt returns more messages than expected for some reason
messages = messages.filter( messages = messages.filter(
(m) => (m) =>
decodeTime(m._id) <= decodeTime(id2) && decodeTime(m.id) <= decodeTime(id2) &&
decodeTime(m._id) >= decodeTime(id1) decodeTime(m.id) >= decodeTime(id1)
); );
} }
// allow single messages too, because why not? // allow single messages too, because why not?
@ -92,11 +92,11 @@ export default {
); );
messages = messages.filter((m) => messages = messages.filter((m) =>
users.find((u) => u?._id == m.author_id) users.find((u) => u?.id == m.authorId)
); );
} }
await message.channel?.deleteMessages(messages.map((m) => m._id)); await message.channel?.deleteMessages(messages.map((m) => m.id));
const replyMsg = await message.channel const replyMsg = await message.channel
?.sendMessage({ ?.sendMessage({
@ -107,8 +107,8 @@ export default {
setTimeout(async () => { setTimeout(async () => {
try { try {
await message.channel?.deleteMessages([ await message.channel?.deleteMessages([
replyMsg!._id, replyMsg!.id,
message._id, message.id,
]); ]);
} catch (e) { } catch (e) {
console.error(e); console.error(e);

View file

@ -45,13 +45,13 @@ export default {
const duration = parseTimeInput(args[1] ?? ''); const duration = parseTimeInput(args[1] ?? '');
if (!duration) { if (!duration) {
await client.api.patch(`/servers/${message.serverContext._id}/members/${target._id}` as '/servers/{server}/members/{target}', { await client.api.patch(`/servers/${message.serverContext.id}/members/${target.id}` as '/servers/{server}/members/{target}', {
timeout: new Date(0).toISOString() timeout: new Date(0).toISOString()
} as any); } as any);
await message.reply(`Timeout cleared on @${target.username}`); await message.reply(`Timeout cleared on @${target.username}`);
} }
else { else {
await client.api.patch(`/servers/${message.serverContext._id}/members/${target._id}` as '/servers/{server}/members/{target}', { await client.api.patch(`/servers/${message.serverContext.id}/members/${target.id}` as '/servers/{server}/members/{target}', {
timeout: new Date(Date.now() + duration).toISOString() timeout: new Date(Date.now() + duration).toISOString()
} as any); } as any);
await message.reply(`Successfully timed out @${target.username}`); await message.reply(`Successfully timed out @${target.username}`);

View file

@ -18,7 +18,7 @@ export default {
} }
let checkTempBans = async (id: string): Promise<number> => { let checkTempBans = async (id: string): Promise<number> => {
let tempbans = await dbs.TEMPBANS.find({ bannedUser: id, server: message.serverContext._id }); let tempbans = await dbs.TEMPBANS.find({ bannedUser: id, server: message.serverContext.id });
if (tempbans.length > 0) { if (tempbans.length > 0) {
for (const ban of tempbans) { for (const ban of tempbans) {
await removeTempBan(ban.id); await removeTempBan(ban.id);
@ -37,7 +37,7 @@ export default {
let id: string|undefined = undefined; let id: string|undefined = undefined;
try { try {
id = (await parseUser(target))?._id; id = (await parseUser(target))?.id;
} catch(e) { } catch(e) {
if (USER_MENTION_REGEX.test(target)) { if (USER_MENTION_REGEX.test(target)) {
id = target id = target
@ -46,8 +46,8 @@ export default {
} else if (ULID_REGEX.test(target)) { } else if (ULID_REGEX.test(target)) {
id = target; id = target;
} else { } else {
let user = bans.users.find(u => u.username.toLowerCase() == target.toLowerCase()); let ban = bans.find(b => b.user?.username.toLowerCase() == target.toLowerCase());
if (user) id = user._id; if (ban) id = ban.id.user;
} }
} }
@ -58,9 +58,9 @@ export default {
} else return msg.edit({ content: 'The user could not be found.' }); } else return msg.edit({ content: 'The user could not be found.' });
} }
let bannedUser = bans.users.find(u => u._id == id); let ban = bans.find(b => b.id.user == id);
if (!bannedUser) { if (!ban) {
let tempnum = await checkTempBans(id); let tempnum = await checkTempBans(id);
if (tempnum > 0) { if (tempnum > 0) {
return msg.edit({ content: 'This user is not banned, but leftover database entries have been cleaned up.' }); return msg.edit({ content: 'This user is not banned, but leftover database entries have been cleaned up.' });
@ -68,12 +68,12 @@ export default {
} }
await Promise.all([ await Promise.all([
msg.edit({ content: `User found: @${bannedUser.username}, unbanning...` }), msg.edit({ content: `User found: @${ban.user?.username ?? ban.id.user}, unbanning...` }),
message.serverContext.unbanUser(id), message.serverContext.unbanUser(id),
checkTempBans(id), checkTempBans(id),
]); ]);
await msg.edit({ content: `@${bannedUser.username} has been unbanned.` }); await msg.edit({ content: `@${ban.user?.username ?? ban.id.user} has been unbanned.` });
} catch(e) { console.error(e) } } catch(e) { console.error(e) }
} }
} as SimpleCommand; } as SimpleCommand;

View file

@ -24,7 +24,7 @@ export default {
category: CommandCategory.Moderation, category: CommandCategory.Moderation,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
try { try {
const serverConfig = await dbs.SERVERS.findOne({ id: message.serverContext._id }); const serverConfig = await dbs.SERVERS.findOne({ id: message.serverContext.id });
if (!serverConfig?.votekick?.enabled) return message.reply('Vote kick is not enabled for this server.'); if (!serverConfig?.votekick?.enabled) return message.reply('Vote kick is not enabled for this server.');
if (!message.member!.roles?.filter(r => serverConfig.votekick?.trustedRoles.includes(r)).length if (!message.member!.roles?.filter(r => serverConfig.votekick?.trustedRoles.includes(r)).length
&& !(await isModerator(message))) { && !(await isModerator(message))) {
@ -47,23 +47,23 @@ export default {
const vote: VoteEntry = { const vote: VoteEntry = {
id: ulid(), id: ulid(),
target: target._id, target: target.id,
user: message.author_id, user: message.authorId!,
server: message.serverContext._id, server: message.serverContext.id,
time: Date.now(), time: Date.now(),
ignore: false, ignore: false,
} }
const votes = await dbs.VOTEKICKS.find({ const votes = await dbs.VOTEKICKS.find({
server: message.serverContext._id, server: message.serverContext.id,
target: target._id, target: target.id,
time: { time: {
$gt: Date.now() - 1000 * 60 * 30, // Last 30 minutes $gt: Date.now() - 1000 * 60 * 30, // Last 30 minutes
}, },
ignore: false, ignore: false,
}); });
if (votes.find(v => v.user == message.author_id)) return message.reply('You can\'t vote twice for this user.'); if (votes.find(v => v.user == message.authorId)) return message.reply('You can\'t vote twice for this user.');
await dbs.VOTEKICKS.insert(vote); await dbs.VOTEKICKS.insert(vote);
votes.push({ _id: '' as any, ...vote }); votes.push({ _id: '' as any, ...vote });
@ -72,7 +72,7 @@ export default {
"votekick", "votekick",
message.serverContext, message.serverContext,
message.member!, message.member!,
target._id, target.id,
`n/a`, `n/a`,
vote.id, vote.id,
`This is vote ${votes.length}/${serverConfig.votekick.votesRequired} for this user.`, `This is vote ${votes.length}/${serverConfig.votekick.votesRequired} for this user.`,
@ -82,15 +82,15 @@ export default {
if (serverConfig.votekick.banDuration == -1) { if (serverConfig.votekick.banDuration == -1) {
targetMember.kick(); targetMember.kick();
} else if (serverConfig.votekick.banDuration == 0) { } else if (serverConfig.votekick.banDuration == 0) {
message.serverContext.banUser(target._id, { reason: 'Automatic permanent ban triggered by /votekick' }); message.serverContext.banUser(target.id, { reason: 'Automatic permanent ban triggered by /votekick' });
} else { } else {
message.serverContext.banUser(target._id, { reason: `Automatic temporary ban triggered by /votekick ` message.serverContext.banUser(target.id, { reason: `Automatic temporary ban triggered by /votekick `
+ `(${serverConfig.votekick.banDuration} minutes)` }); + `(${serverConfig.votekick.banDuration} minutes)` });
await storeTempBan({ await storeTempBan({
id: ulid(), id: ulid(),
bannedUser: target._id, bannedUser: target.id,
server: message.serverContext._id, server: message.serverContext.id,
until: Date.now() + (1000 * 60 * serverConfig.votekick.banDuration), until: Date.now() + (1000 * 60 * serverConfig.votekick.banDuration),
}); });
} }
@ -99,8 +99,8 @@ export default {
+ `Banned @${target.username} for ${serverConfig.votekick.banDuration} minutes.`); // Todo: display ban duration properly (Permban, kick, etc) + `Banned @${target.username} for ${serverConfig.votekick.banDuration} minutes.`); // Todo: display ban duration properly (Permban, kick, etc)
await dbs.VOTEKICKS.update({ await dbs.VOTEKICKS.update({
server: message.serverContext._id, server: message.serverContext.id,
target: target._id, target: target.id,
time: { $gt: Date.now() - 1000 * 60 * 30 }, time: { $gt: Date.now() - 1000 * 60 * 30 },
ignore: false, ignore: false,
}, { $set: { ignore: true } }); }, { $set: { ignore: true } });

View file

@ -6,7 +6,7 @@ import InfractionType from "automod/dist/types/antispam/InfractionType";
import { fetchUsername, logModAction } from "../../modules/mod_logs"; import { fetchUsername, logModAction } from "../../modules/mod_logs";
import CommandCategory from "../../../struct/commands/CommandCategory"; import CommandCategory from "../../../struct/commands/CommandCategory";
import { SendableEmbed } from "revolt-api"; import { SendableEmbed } from "revolt-api";
import { User } from "@janderedev/revolt.js"; import { User } from "revolt.js";
import logger from "../../logger"; import logger from "../../logger";
export default { export default {
@ -19,7 +19,7 @@ export default {
if (!await isModerator(message)) return message.reply(NO_MANAGER_MSG); if (!await isModerator(message)) return message.reply(NO_MANAGER_MSG);
const userInput = args.shift() || ''; const userInput = args.shift() || '';
if (!userInput && !message.reply_ids?.length) return message.reply({ embeds: [ if (!userInput && !message.replyIds?.length) return message.reply({ embeds: [
embed( embed(
`Please specify one or more users by replying to their message while running this command or ` + `Please specify one or more users by replying to their message while running this command or ` +
`by specifying a comma-separated list of usernames.`, `by specifying a comma-separated list of usernames.`,
@ -38,12 +38,12 @@ export default {
const embeds: SendableEmbed[] = []; const embeds: SendableEmbed[] = [];
const handledUsers: string[] = []; const handledUsers: string[] = [];
const targetUsers: User|{ _id: string }[] = []; const targetUsers: User|{ id: string }[] = [];
const targetInput = dedupeArray( const targetInput = dedupeArray(
// Replied messages // Replied messages
(await Promise.allSettled( (await Promise.allSettled(
(message.reply_ids ?? []).map(msg => message.channel?.fetchMessage(msg)) (message.replyIds ?? []).map(msg => message.channel?.fetchMessage(msg))
)) ))
.filter(m => m.status == 'fulfilled').map(m => (m as any).value.author_id), .filter(m => m.status == 'fulfilled').map(m => (m as any).value.author_id),
// Provided users // Provided users
@ -54,7 +54,7 @@ export default {
try { try {
let user = await parseUserOrId(userStr); let user = await parseUserOrId(userStr);
if (!user) { if (!user) {
if (message.reply_ids?.length && userStr == userInput) { if (message.replyIds?.length && userStr == userInput) {
reason = reason ? `${userInput} ${reason}` : userInput; reason = reason ? `${userInput} ${reason}` : userInput;
} }
else { else {
@ -64,8 +64,8 @@ export default {
} }
// Silently ignore duplicates // Silently ignore duplicates
if (handledUsers.includes(user._id)) continue; if (handledUsers.includes(user.id)) continue;
handledUsers.push(user._id); handledUsers.push(user.id);
if ((user as any)?.bot != null) return await message.reply({ embeds: [ if ((user as any)?.bot != null) return await message.reply({ embeds: [
embed('You cannot warn bots.', null, EmbedColor.SoftError) embed('You cannot warn bots.', null, EmbedColor.SoftError)
@ -85,10 +85,10 @@ export default {
for (const user of targetUsers) { for (const user of targetUsers) {
let infraction = { let infraction = {
_id: ulid(), _id: ulid(),
createdBy: message.author_id, createdBy: message.authorId,
user: user._id, user: user.id,
reason: reason || 'No reason provided', reason: reason || 'No reason provided',
server: message.serverContext._id, server: message.serverContext.id,
type: InfractionType.Manual, type: InfractionType.Manual,
date: Date.now(), date: Date.now(),
} as Infraction; } as Infraction;
@ -99,7 +99,7 @@ export default {
'warn', 'warn',
message.serverContext, message.serverContext,
message.member!, message.member!,
user._id, user.id,
reason || 'No reason provided', reason || 'No reason provided',
infraction._id, infraction._id,
`This is warn number ${userWarnCount} for this user.` `This is warn number ${userWarnCount} for this user.`
@ -123,10 +123,10 @@ export default {
embeds.push({ embeds.push({
title: `User warned`, title: `User warned`,
icon_url: user instanceof User ? user.generateAvatarURL() : undefined, icon_url: user instanceof User ? user.avatarURL : undefined,
colour: EmbedColor.Success, colour: EmbedColor.Success,
description: `This is ${userWarnCount == 1 ? '**the first warn**' : `warn number **${userWarnCount}**`}` + description: `This is ${userWarnCount == 1 ? '**the first warn**' : `warn number **${userWarnCount}**`}` +
` for ${await fetchUsername(user._id)}.\n` + ` for ${await fetchUsername(user.id)}.\n` +
`**Infraction ID:** \`${infraction._id}\`\n` + `**Infraction ID:** \`${infraction._id}\`\n` +
`**Reason:** \`${infraction.reason}\`` `**Reason:** \`${infraction.reason}\``
}); });

View file

@ -23,7 +23,7 @@ export default {
category: CommandCategory.Moderation, category: CommandCategory.Moderation,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
let infractions: Array<Infraction> = await dbs.INFRACTIONS.find({ let infractions: Array<Infraction> = await dbs.INFRACTIONS.find({
server: message.serverContext._id, server: message.serverContext.id,
}); });
let userInfractions: Map<string, Infraction[]> = new Map(); let userInfractions: Map<string, Infraction[]> = new Map();
infractions.forEach(i => { infractions.forEach(i => {
@ -56,7 +56,7 @@ export default {
if (!id) return message.reply('No infraction ID provided.'); if (!id) return message.reply('No infraction ID provided.');
let inf = await dbs.INFRACTIONS.findOneAndDelete({ let inf = await dbs.INFRACTIONS.findOneAndDelete({
_id: { $eq: id.toUpperCase() }, _id: { $eq: id.toUpperCase() },
server: message.serverContext._id server: message.serverContext.id
}); });
if (!inf) return message.reply('I can\'t find that ID.'); if (!inf) return message.reply('I can\'t find that ID.');
@ -69,18 +69,18 @@ export default {
break; break;
default: default:
let user = await parseUserOrId(args[0]); let user = await parseUserOrId(args[0]);
if (!user?._id) return message.reply('I can\'t find this user.'); if (!user?.id) return message.reply('I can\'t find this user.');
if (user._id != message.author_id && !await isModerator(message)) return message.reply(NO_MANAGER_MSG); if (user.id != message.authorId && !await isModerator(message)) return message.reply(NO_MANAGER_MSG);
const infs = userInfractions.get(user._id); const infs = userInfractions.get(user.id);
const userConfig = await dbs.USERS.findOne({ id: user._id }); const userConfig = await dbs.USERS.findOne({ id: user.id });
if (!infs) return message.reply(`There are no infractions stored for \`${await fetchUsername(user._id)}\`.` if (!infs) return message.reply(`There are no infractions stored for \`${await fetchUsername(user.id)}\`.`
+ (userConfig?.globalBlacklist ? '\n' + GLOBAL_BLACKLIST_TEXT(userConfig.blacklistReason) : ''), false); + (userConfig?.globalBlacklist ? '\n' + GLOBAL_BLACKLIST_TEXT(userConfig.blacklistReason) : ''), false);
else { else {
let msg = `## ${infs.length} infractions stored for ${await fetchUsername(user._id)}\n`; let msg = `## ${infs.length} infractions stored for ${await fetchUsername(user.id)}\n`;
if (userConfig?.globalBlacklist) { if (userConfig?.globalBlacklist) {
msg += GLOBAL_BLACKLIST_TEXT(userConfig.blacklistReason); msg += GLOBAL_BLACKLIST_TEXT(userConfig.blacklistReason);
@ -108,7 +108,7 @@ export default {
if (attachSpreadsheet) { if (attachSpreadsheet) {
try { try {
let csv_data = [ let csv_data = [
[`Warns for ${await fetchUsername(user._id)} (${user._id}) - ${Day().toString()}`], [`Warns for ${await fetchUsername(user.id)} (${user.id}) - ${Day().toString()}`],
[], [],
['Date', 'Reason', 'Created By', 'Type', 'Action Type', 'ID'], ['Date', 'Reason', 'Created By', 'Type', 'Action Type', 'ID'],
]; ];
@ -127,7 +127,7 @@ export default {
let sheet = Xlsx.utils.aoa_to_sheet(csv_data); let sheet = Xlsx.utils.aoa_to_sheet(csv_data);
let csv = Xlsx.utils.sheet_to_csv(sheet); let csv = Xlsx.utils.sheet_to_csv(sheet);
message.reply({ content: msg, attachments: [ await uploadFile(csv, `${user._id}.csv`) ] }, false); message.reply({ content: msg, attachments: [ await uploadFile(csv, `${user.id}.csv`) ] }, false);
} catch(e) { } catch(e) {
console.error(e); console.error(e);
message.reply(msg, false); message.reply(msg, false);

View file

@ -29,7 +29,7 @@ async function adminBotLog(data: { message: string, type: 'INFO'|'WARN'|'ERROR'
await client?.send({ await client?.send({
embeds: [ embed ], embeds: [ embed ],
username: bot.user?.username, username: bot.user?.username,
avatarURL: bot.user?.generateAvatarURL({ size: 128 }) avatarURL: bot.user?.avatarURL,
}); });
} catch(e) { } catch(e) {
logger.error(`Failed to log: ${e}`); logger.error(`Failed to log: ${e}`);

View file

@ -1,4 +1,4 @@
import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { Message } from "revolt.js";
import { ulid } from "ulid"; import { ulid } from "ulid";
import { client, dbs } from "../.."; import { client, dbs } from "../..";
import AntispamRule from "automod/dist/types/antispam/AntispamRule"; import AntispamRule from "automod/dist/types/antispam/AntispamRule";
@ -23,7 +23,7 @@ const SENT_FILTER_MESSAGE: string[] = [];
*/ */
async function antispam(message: Message): Promise<boolean> { async function antispam(message: Message): Promise<boolean> {
try { try {
let serverRules = await dbs.SERVERS.findOne({ id: message.channel!.server_id! }); let serverRules = await dbs.SERVERS.findOne({ id: message.channel!.serverId! });
if (!serverRules?.automodSettings) return true; if (!serverRules?.automodSettings) return true;
let ruleTriggered = false; let ruleTriggered = false;
@ -34,14 +34,14 @@ async function antispam(message: Message): Promise<boolean> {
} }
if (message.author?.bot != null) break; if (message.author?.bot != null) break;
if (serverRules.whitelist?.users?.includes(message.author_id)) break; if (serverRules.whitelist?.users?.includes(message.authorId!)) break;
if (message.member?.roles?.filter(r => serverRules!.whitelist?.roles?.includes(r)).length) break; if (message.member?.roles?.filter(r => serverRules!.whitelist?.roles?.includes(r)).length) break;
if (serverRules.whitelist?.managers !== false && await isModerator(message, false)) break; if (serverRules.whitelist?.managers !== false && await isModerator(message, false)) break;
if (rule.channels?.length && rule.channels.indexOf(message.channel_id) == -1) break; if (rule.channels?.length && rule.channels.indexOf(message.channelId) == -1) break;
let store = msgCountStore.get(rule.id)!; let store = msgCountStore.get(rule.id)!;
if (!store.users[message.channel_id]) store.users[message.channel_id] = {} if (!store.users[message.channelId]) store.users[message.channelId] = {}
let userStore = store.users[message.channel_id]; let userStore = store.users[message.channelId];
if (!userStore.count) userStore.count = 1; if (!userStore.count) userStore.count = 1;
else userStore.count++; else userStore.count++;
@ -75,9 +75,9 @@ async function antispam(message: Message): Promise<boolean> {
createdBy: null, createdBy: null,
date: Date.now(), date: Date.now(),
reason: `Automatic moderation rule triggered: More than ${rule.max_msg} messages per ${rule.timeframe} seconds.`, reason: `Automatic moderation rule triggered: More than ${rule.max_msg} messages per ${rule.timeframe} seconds.`,
server: message.channel?.server_id, server: message.channel?.serverId,
type: InfractionType.Automatic, type: InfractionType.Automatic,
user: message.author_id, user: message.authorId,
} as Infraction; } as Infraction;
message.channel?.sendMessage('## User has been warned.\n\u200b\n' + getWarnMsg(rule, message)) message.channel?.sendMessage('## User has been warned.\n\u200b\n' + getWarnMsg(rule, message))
@ -107,8 +107,8 @@ async function antispam(message: Message): Promise<boolean> {
function getWarnMsg(rule: AntispamRule, message: Message) { function getWarnMsg(rule: AntispamRule, message: Message) {
if (rule.message != null) { if (rule.message != null) {
return rule.message return rule.message
.replace(new RegExp('{{userid}}', 'gi'), message.author_id); .replace(new RegExp('{{userid}}', 'gi'), message.authorId!);
} else return `<@${message.author_id}>, please stop spamming.`; } else return `<@${message.authorId}>, please stop spamming.`;
} }
/** /**
@ -133,9 +133,9 @@ async function wordFilterCheck(message: Message, config: ServerConfig) {
createdBy: null, createdBy: null,
date: Date.now(), date: Date.now(),
reason: 'Word filter triggered', reason: 'Word filter triggered',
server: message.channel!.server_id!, server: message.channel!.serverId!,
type: InfractionType.Automatic, type: InfractionType.Automatic,
user: message.author_id, user: message.authorId!,
} }
await storeInfraction(infraction); await storeInfraction(infraction);
@ -155,14 +155,14 @@ async function wordFilterCheck(message: Message, config: ServerConfig) {
} }
case 'DELETE': { case 'DELETE': {
if (message.channel?.havePermission('ManageMessages')) { if (message.channel?.havePermission('ManageMessages')) {
const key = `${message.author_id}:${message.channel_id}`; const key = `${message.authorId}:${message.channelId}`;
await message.delete(); await message.delete();
if (!SENT_FILTER_MESSAGE.includes(key)) { if (!SENT_FILTER_MESSAGE.includes(key)) {
SENT_FILTER_MESSAGE.push(key); SENT_FILTER_MESSAGE.push(key);
setTimeout(() => SENT_FILTER_MESSAGE.splice(SENT_FILTER_MESSAGE.indexOf(key), 1), 30000); setTimeout(() => SENT_FILTER_MESSAGE.splice(SENT_FILTER_MESSAGE.indexOf(key), 1), 30000);
await message.channel.sendMessage((config.wordlistAction.message || WORDLIST_DEFAULT_MESSAGE) await message.channel.sendMessage((config.wordlistAction.message || WORDLIST_DEFAULT_MESSAGE)
.replaceAll('{{user_id}}', message.author_id)); .replaceAll('{{user_id}}', message.authorId!));
} }
} }
} }
@ -171,7 +171,7 @@ async function wordFilterCheck(message: Message, config: ServerConfig) {
if (!config.logs?.modAction) break; if (!config.logs?.modAction) break;
await sendLogMessage(config.logs.modAction, { await sendLogMessage(config.logs.modAction, {
title: 'Message triggered word filter', title: 'Message triggered word filter',
description: `**Author:** @${message.author?.username} (${message.author_id})\n` + description: `**Author:** @${message.author?.username} (${message.authorId})\n` +
`**Action:** ${config.wordlistAction?.action || 'LOG'}\n` + `**Action:** ${config.wordlistAction?.action || 'LOG'}\n` +
`#### Content\n` + `#### Content\n` +
`>${sanitizeMessageContent(message.content.substring(0, 1000)).trim().replace(/\n/g, '\n>')}`, `>${sanitizeMessageContent(message.content.substring(0, 1000)).trim().replace(/\n/g, '\n>')}`,
@ -259,7 +259,7 @@ const notifyPublicServers = async () => {
.filter(server => server.discoverable); .filter(server => server.discoverable);
const res = await dbs.SERVERS.find({ const res = await dbs.SERVERS.find({
id: { $in: servers.map(s => s._id) }, id: { $in: servers.map(s => s.id) },
discoverAutospamNotify: { $in: [ undefined, false ] }, discoverAutospamNotify: { $in: [ undefined, false ] },
}); });
@ -273,7 +273,7 @@ const notifyPublicServers = async () => {
); );
const server = client.servers.get(serverConfig.id); const server = client.servers.get(serverConfig.id);
const channel = await getDmChannel(server!.owner); const channel = await getDmChannel(server!.ownerId);
await channel.sendMessage(`Hi there, await channel.sendMessage(`Hi there,
It looks like your server, **${sanitizeMessageContent(server!.name).trim()}**, has been added to server discovery. Congratulations! It looks like your server, **${sanitizeMessageContent(server!.name).trim()}**, has been added to server discovery. Congratulations!

View file

@ -1,5 +1,5 @@
import { Member } from "@janderedev/revolt.js/dist/maps/Members"; import { ServerMember } from "revolt.js";
import { User } from "@janderedev/revolt.js/dist/maps/Users"; import { User } from "revolt.js";
import { client, dbs } from "../../.."; import { client, dbs } from "../../..";
import ServerConfig from "automod/dist/types/ServerConfig"; import ServerConfig from "automod/dist/types/ServerConfig";
import { getPermissionLevel } from "../../util"; import { getPermissionLevel } from "../../util";
@ -37,7 +37,7 @@ wsEvents.on('req:getUserServerDetails', async (data: ReqData, cb: (data: WSRespo
return; return;
} }
let member: Member; let member: ServerMember;
try { try {
member = await server.fetchMember(user); member = await server.fetchMember(user);
} catch(e) { } catch(e) {
@ -45,7 +45,7 @@ wsEvents.on('req:getUserServerDetails', async (data: ReqData, cb: (data: WSRespo
return; return;
} }
const serverConfig = await dbs.SERVERS.findOne({ id: server._id }); const serverConfig = await dbs.SERVERS.findOne({ id: server.id });
// todo: remove unwanted keys from server config // todo: remove unwanted keys from server config
@ -60,28 +60,28 @@ wsEvents.on('req:getUserServerDetails', async (data: ReqData, cb: (data: WSRespo
const users = await Promise.allSettled([ const users = await Promise.allSettled([
...(serverConfig?.botManagers?.map(u => fetchUser(u)) ?? []), ...(serverConfig?.botManagers?.map(u => fetchUser(u)) ?? []),
...(serverConfig?.moderators?.map(u => fetchUser(u)) ?? []), ...(serverConfig?.moderators?.map(u => fetchUser(u)) ?? []),
fetchUser(user._id), fetchUser(user.id),
]); ]);
const response: ServerDetails = { const response: ServerDetails = {
id: server._id, id: server.id,
name: server.name, name: server.name,
perms: await getPermissionLevel(member, server), perms: await getPermissionLevel(member, server),
description: server.description ?? undefined, description: server.description ?? undefined,
bannerURL: server.generateBannerURL(), bannerURL: server.bannerURL,
iconURL: server.generateIconURL(), iconURL: server.iconURL,
serverConfig: (serverConfig as ServerConfig|undefined), serverConfig: (serverConfig as ServerConfig|undefined),
users: users.map( users: users.map(
u => u.status == 'fulfilled' u => u.status == 'fulfilled'
? { id: u.value._id, avatarURL: u.value.generateAvatarURL(), username: u.value.username } ? { id: u.value.id, avatarURL: u.value.avatarURL, username: u.value.username }
: { id: u.reason } : { id: u.reason }
), ),
channels: server.channels.filter(c => c != undefined).map(c => ({ channels: server.channels.filter(c => c != undefined).map(c => ({
id: c!._id, id: c!.id,
name: c!.name ?? '', name: c!.name ?? '',
nsfw: c!.nsfw ?? false, nsfw: false, // todo?
type: c!.channel_type == 'VoiceChannel' ? 'VOICE' : 'TEXT', type: c!.type == 'VoiceChannel' ? 'VOICE' : 'TEXT',
icon: c!.generateIconURL(), icon: c!.iconURL,
})), })),
dmOnKick: serverConfig?.dmOnKick, dmOnKick: serverConfig?.dmOnKick,
dmOnWarn: serverConfig?.dmOnWarn, dmOnWarn: serverConfig?.dmOnWarn,

View file

@ -1,4 +1,4 @@
import { User } from '@janderedev/revolt.js/dist/maps/Users'; import { User } from 'revolt.js';
import { client } from '../../..'; import { client } from '../../..';
import { getMutualServers, getPermissionLevel } from '../../util'; import { getMutualServers, getPermissionLevel } from '../../util';
import { wsEvents, WSResponse } from '../api_communication'; import { wsEvents, WSResponse } from '../api_communication';
@ -27,11 +27,11 @@ wsEvents.on('req:getUserServers', async (data: ReqData, cb: (data: WSResponse) =
if (!server) return reject('Server not found'); if (!server) return reject('Server not found');
const perms = await getPermissionLevel(user, server); const perms = await getPermissionLevel(user, server);
resolve({ resolve({
id: server._id, id: server.id,
perms, perms,
name: server.name, name: server.name,
bannerURL: server.generateBannerURL(), bannerURL: server.bannerURL,
iconURL: server.generateIconURL({}), iconURL: server.iconURL,
}); });
} catch(e) { } catch(e) {
console.error(e); console.error(e);

View file

@ -1,4 +1,4 @@
import { User } from "@janderedev/revolt.js/dist/maps/Users"; import { User } from "revolt.js";
import { client } from "../../.."; import { client } from "../../..";
import { getPermissionLevel, parseUser } from "../../util"; import { getPermissionLevel, parseUser } from "../../util";
import { wsEvents, WSResponse } from "../api_communication"; import { wsEvents, WSResponse } from "../api_communication";
@ -30,7 +30,7 @@ wsEvents.on('req:getUser', async (data: { user: string }, cb: (data: WSResponse)
if (!user) if (!user)
cb({ success: false, statusCode: 404, error: 'User could not be found' }); cb({ success: false, statusCode: 404, error: 'User could not be found' });
else else
cb({ success: true, user: { id: user._id, username: user.username, avatarURL: user.generateAvatarURL() } as APIUser }); cb({ success: true, user: { id: user.id, username: user.username, avatarURL: user.avatarURL } as APIUser });
} catch(e) { } catch(e) {
console.error(e); console.error(e);
cb({ success: false, error: `${e}` }); cb({ success: false, error: `${e}` });

View file

@ -102,18 +102,18 @@ wsEvents.on('req:requestLogin', async (data: any, cb: (data: WSResponse) => void
let code: string|null = null; let code: string|null = null;
while (!code) { while (!code) {
const c = crypto.randomBytes(8).toString('hex'); const c = crypto.randomBytes(8).toString('hex');
const found = await dbs.PENDING_LOGINS.find({ code: c, user: user._id, confirmed: false }); const found = await dbs.PENDING_LOGINS.find({ code: c, user: user.id, confirmed: false });
if (found.length > 0) continue; if (found.length > 0) continue;
code = c.substring(0, 8).toUpperCase(); code = c.substring(0, 8).toUpperCase();
} }
logger.info(`Attempted login for user ${user._id} with code ${code}`); logger.info(`Attempted login for user ${user.id} with code ${code}`);
const nonce = ulid(); const nonce = ulid();
const [previousLogins, currentValidLogins] = await Promise.all([ const [previousLogins, currentValidLogins] = await Promise.all([
dbs.PENDING_LOGINS.find({ user: user._id, confirmed: true }), dbs.PENDING_LOGINS.find({ user: user.id, confirmed: true }),
dbs.PENDING_LOGINS.find({ user: user._id, confirmed: false, expires: { $gt: Date.now() } }), dbs.PENDING_LOGINS.find({ user: user.id, confirmed: false, expires: { $gt: Date.now() } }),
]); ]);
if (currentValidLogins.length >= 5) return cb({ success: false, statusCode: 403, error: 'Too many pending logins. Try again later.' }); if (currentValidLogins.length >= 5) return cb({ success: false, statusCode: 403, error: 'Too many pending logins. Try again later.' });
@ -121,7 +121,7 @@ wsEvents.on('req:requestLogin', async (data: any, cb: (data: WSResponse) => void
await dbs.PENDING_LOGINS.insert({ await dbs.PENDING_LOGINS.insert({
code, code,
expires: Date.now() + (1000 * 60 * 15), // Expires in 15 minutes expires: Date.now() + (1000 * 60 * 15), // Expires in 15 minutes
user: user._id, user: user.id,
nonce: nonce, nonce: nonce,
confirmed: false, confirmed: false,
requirePhishingConfirmation: previousLogins.length == 0, requirePhishingConfirmation: previousLogins.length == 0,
@ -129,7 +129,7 @@ wsEvents.on('req:requestLogin', async (data: any, cb: (data: WSResponse) => void
invalid: false, invalid: false,
} as PendingLogin); } as PendingLogin);
cb({ success: true, uid: user._id, nonce, code }); cb({ success: true, uid: user.id, nonce, code });
} catch(e) { } catch(e) {
console.error(e); console.error(e);
cb({ success: false, error: `${e}` }); cb({ success: false, error: `${e}` });
@ -137,7 +137,7 @@ wsEvents.on('req:requestLogin', async (data: any, cb: (data: WSResponse) => void
}); });
wsEvents.on('req:stats', async (_data: any, cb: (data: { servers: number }) => void) => { wsEvents.on('req:stats', async (_data: any, cb: (data: { servers: number }) => void) => {
const servers = bot.servers.size; const servers = bot.servers.size();
cb({ servers }); cb({ servers });
}); });

View file

@ -15,10 +15,10 @@ import logger from "../logger";
const update = async () => { const update = async () => {
try { try {
const statusText = statuses[i] const statusText = statuses[i]
.replace('{{servers}}', `${client.servers.size}`) .replace('{{servers}}', `${client.servers.size()}`)
.replace('{{users}}', `${client.users.size}`) .replace('{{users}}', `${client.users.size()}`)
.replace('{{infractions_total}}', `${await dbs.INFRACTIONS.count({})}`) .replace('{{infractions_total}}', `${await dbs.INFRACTIONS.count({})}`)
.replace('{{ping_ms}}', `${client.websocket.ping ?? -1}`); .replace('{{ping_ms}}', `${client.events.ping() ?? -1}`);
await setStatus(statusText, 'Online'); await setStatus(statusText, 'Online');
logger.debug(`Bot status updated`); logger.debug(`Bot status updated`);
@ -37,7 +37,7 @@ import logger from "../logger";
async function setStatus(text: string, presence: 'Online'|'Idle'|'Busy'|'Invisible') { async function setStatus(text: string, presence: 'Online'|'Idle'|'Busy'|'Invisible') {
await axios.patch( await axios.patch(
`${client.apiURL}/users/@me`, `${client.options.baseURL}/users/@me`,
{ {
status: { text, presence } status: { text, presence }
}, },

View file

@ -7,7 +7,7 @@ import { antispam, wordFilterCheck } from "./antispam";
import checkCustomRules from "./custom_rules/custom_rules"; import checkCustomRules from "./custom_rules/custom_rules";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
import { getOwnMemberInServer, hasPermForChannel } from "../util"; import { getOwnMemberInServer } from "../util";
import { isSudo, updateSudoTimeout } from "../commands/admin/botadm"; import { isSudo, updateSudoTimeout } from "../commands/admin/botadm";
import { metrics } from "./metrics"; import { metrics } from "./metrics";
@ -30,20 +30,20 @@ let commands: SimpleCommand[];
.map(async file => await import(file) as SimpleCommand) .map(async file => await import(file) as SimpleCommand)
)).map(c => (c as any).default) )).map(c => (c as any).default)
client.on('message/update', async msg => { client.on('messageUpdate', async msg => {
checkCustomRules(msg, true); checkCustomRules(msg, true);
}); });
client.on('message', async msg => { client.on('messageCreate', async msg => {
logger.debug(`Message -> ${msg.content}`); logger.debug(`Message -> ${msg.content}`);
if (typeof msg.content != 'string' || if (typeof msg.content != 'string' ||
msg.author_id == client.user?._id || msg.authorId == client.user?.id ||
!msg.channel?.server) return; !msg.channel?.server) return;
try { try {
if (!msg.member) await msg.channel.server.fetchMember(msg.author_id); if (!msg.member) await msg.channel.server.fetchMember(msg.authorId!);
if (!msg.author) await client.users.fetch(msg.author_id); if (!msg.author) await client.users.fetch(msg.authorId!);
} catch(e) { } catch(e) {
return msg.reply('⚠ Failed to fetch message author'); return msg.reply('⚠ Failed to fetch message author');
} }
@ -51,7 +51,8 @@ let commands: SimpleCommand[];
if (msg.author!.bot) return; if (msg.author!.bot) return;
// If we can't reply to the message, return // If we can't reply to the message, return
if (!hasPermForChannel(await getOwnMemberInServer(msg.channel.server), msg.channel, 'SendMessage')) { const member = await getOwnMemberInServer(msg.channel.server);
if (!member.hasPermission(msg.channel, 'SendMessage')) {
logger.debug('Cannot reply to message; returning'); logger.debug('Cannot reply to message; returning');
return; return;
} }
@ -61,8 +62,8 @@ let commands: SimpleCommand[];
checkCustomRules(msg); checkCustomRules(msg);
let [ config, userConfig ] = await Promise.all([ let [ config, userConfig ] = await Promise.all([
dbs.SERVERS.findOne({ id: msg.channel!.server_id! }), dbs.SERVERS.findOne({ id: msg.channel!.serverId! }),
dbs.USERS.findOne({ id: msg.author_id }), dbs.USERS.findOne({ id: msg.authorId }),
]); ]);
if (config) { if (config) {
@ -75,8 +76,8 @@ let commands: SimpleCommand[];
let cmdName = args.shift() ?? ''; let cmdName = args.shift() ?? '';
let guildPrefix = config?.prefix ?? DEFAULT_PREFIX; let guildPrefix = config?.prefix ?? DEFAULT_PREFIX;
if (cmdName.startsWith(`<@${client.user?._id}>`)) { if (cmdName.startsWith(`<@${client.user?.id}>`)) {
cmdName = cmdName.substring(`<@${client.user?._id}>`.length); cmdName = cmdName.substring(`<@${client.user?.id}>`.length);
if (!cmdName) cmdName = args.shift() ?? ''; // Space between mention and command name if (!cmdName) cmdName = args.shift() ?? ''; // Space between mention and command name
} else if (cmdName.startsWith(guildPrefix)) { } else if (cmdName.startsWith(guildPrefix)) {
cmdName = cmdName.substring(guildPrefix.length); cmdName = cmdName.substring(guildPrefix.length);
@ -108,7 +109,7 @@ let commands: SimpleCommand[];
if (isSudo(msg.author!)) updateSudoTimeout(msg.author!); if (isSudo(msg.author!)) updateSudoTimeout(msg.author!);
if (cmd.restrict == 'BOTOWNER' && ownerIDs.indexOf(msg.author_id) == -1) { if (cmd.restrict == 'BOTOWNER' && ownerIDs.indexOf(msg.authorId!) == -1) {
logger.warn(`User ${msg.author?.username} tried to run owner-only command: ${cmdName}`); logger.warn(`User ${msg.author?.username} tried to run owner-only command: ${cmdName}`);
msg.reply('🔒 Access denied'); msg.reply('🔒 Access denied');
return; return;
@ -130,10 +131,10 @@ let commands: SimpleCommand[];
let message: MessageCommandContext = msg as MessageCommandContext; let message: MessageCommandContext = msg as MessageCommandContext;
message.serverContext = serverCtx; message.serverContext = serverCtx;
logger.info(`Command: ${message.author?.username} (${message.author?._id}) in ${message.channel?.server?.name} (${message.channel?.server?._id}): ${message.content}`); logger.info(`Command: ${message.author?.username} (${message.author?.id}) in ${message.channel?.server?.name} (${message.channel?.serverId}): ${message.content}`);
// Create document for server in DB, if not already present // Create document for server in DB, if not already present
if (JSON.stringify(config) == '{}' || !config) await dbs.SERVERS.insert({ id: message.channel!.server_id! }); if (JSON.stringify(config) == '{}' || !config) await dbs.SERVERS.insert({ id: message.channel!.serverId! });
if (cmd.removeEmptyArgs !== false) { if (cmd.removeEmptyArgs !== false) {
args = args.filter(a => a.length > 0); args = args.filter(a => a.length > 0);

View file

@ -1,4 +1,4 @@
import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { Message } from "revolt.js";
import CustomRuleAction from "automod/dist/types/antispam/CustomRuleAction"; import CustomRuleAction from "automod/dist/types/antispam/CustomRuleAction";
async function execute(message: Message, action: CustomRuleAction) { async function execute(message: Message, action: CustomRuleAction) {

View file

@ -1,4 +1,4 @@
import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { Message } from "revolt.js";
import { client } from "../../../.."; import { client } from "../../../..";
import CustomRuleAction from "automod/dist/types/antispam/CustomRuleAction"; import CustomRuleAction from "automod/dist/types/antispam/CustomRuleAction";
@ -8,7 +8,7 @@ async function execute(message: Message, action: CustomRuleAction) {
text = text.slice(0, 1996) + ' ...'; text = text.slice(0, 1996) + ' ...';
} }
if (!message.channel) await client.channels.fetch(message.channel_id); if (!message.channel) await client.channels.fetch(message.channelId);
let msg = await message.channel!.sendMessage(text); let msg = await message.channel!.sendMessage(text);
if (action.duration) { if (action.duration) {

View file

@ -1,4 +1,4 @@
import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { Message } from "revolt.js";
import CustomRuleAction from "automod/dist/types/antispam/CustomRuleAction"; import CustomRuleAction from "automod/dist/types/antispam/CustomRuleAction";
import { storeInfraction } from '../../../util'; import { storeInfraction } from '../../../util';
import Infraction from "automod/dist/types/antispam/Infraction"; import Infraction from "automod/dist/types/antispam/Infraction";
@ -7,17 +7,17 @@ import InfractionType from "automod/dist/types/antispam/InfractionType";
async function execute(message: Message, action: CustomRuleAction) { async function execute(message: Message, action: CustomRuleAction) {
let warnMsg = action.text let warnMsg = action.text
? `${action.text}\n(Triggered on ${message.channel_id} / ${message._id})` ? `${action.text}\n(Triggered on ${message.channelId} / ${message.id})`
: `Moderation rule triggered on ${message.channel_id} / ${message._id}`; : `Moderation rule triggered on ${message.channelId} / ${message.id}`;
let infraction: Infraction = { let infraction: Infraction = {
_id: ulid(), _id: ulid(),
date: Date.now(), date: Date.now(),
createdBy: null, createdBy: null,
reason: warnMsg, reason: warnMsg,
server: message.channel?.server_id!, server: message.channel?.serverId!,
type: InfractionType.Automatic, type: InfractionType.Automatic,
user: message.author_id user: message.authorId!,
} }
let { userWarnCount } = await storeInfraction(infraction); let { userWarnCount } = await storeInfraction(infraction);

View file

@ -1,4 +1,4 @@
import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { Message } from "revolt.js";
import { dbs } from "../../.."; import { dbs } from "../../..";
import logger from "../../logger"; import logger from "../../logger";
import messageContentTrigger from "./message_content_trigger"; import messageContentTrigger from "./message_content_trigger";
@ -6,11 +6,11 @@ import messageContentTrigger from "./message_content_trigger";
import custom_sendMessage from "./actions/sendMessage"; import custom_sendMessage from "./actions/sendMessage";
import custom_delete from "./actions/delete"; import custom_delete from "./actions/delete";
import custom_warn from "./actions/warn"; import custom_warn from "./actions/warn";
import { getOwnMemberInServer, hasPermForChannel } from "../../util"; import { getOwnMemberInServer } from "../../util";
async function checkCustomRules(message: Message, isEdit: boolean = false) { async function checkCustomRules(message: Message, isEdit: boolean = false) {
try { try {
let serverConfig = await dbs.SERVERS.findOne({ id: message.channel!.server_id! }); let serverConfig = await dbs.SERVERS.findOne({ id: message.channel!.serverId! });
let rules = serverConfig?.automodSettings?.custom; let rules = serverConfig?.automodSettings?.custom;
if (!rules) return; if (!rules) return;
@ -24,27 +24,28 @@ async function checkCustomRules(message: Message, isEdit: boolean = false) {
if (await messageContentTrigger(message, rule.trigger)) { if (await messageContentTrigger(message, rule.trigger)) {
for (const action of rule.action) { for (const action of rule.action) {
const member = await getOwnMemberInServer(message.channel!.server!);
switch(action.action) { switch(action.action) {
case 'sendMessage': case 'sendMessage':
if (hasPermForChannel(await getOwnMemberInServer(message.channel!.server!), message.channel!, 'SendMessage')) if (member.hasPermission(message.channel!, 'SendMessage'))
await custom_sendMessage(message, action); await custom_sendMessage(message, action);
else else
logger.warn(`Custom rule ${rule._id}: 'sendMessage' action lacks permission`); logger.warn(`Custom rule ${rule._id}: 'sendMessage' action lacks permission`);
break; break;
case 'delete': case 'delete':
if (hasPermForChannel(await getOwnMemberInServer(message.channel!.server!), message.channel!, 'ManageMessages')) if (member.hasPermission(message.channel!, 'ManageMessages'))
await custom_delete(message, action); await custom_delete(message, action);
else else
logger.warn(`Custom rule ${rule._id}: 'delete' action lacks permission`); logger.warn(`Custom rule ${rule._id}: 'delete' action lacks permission`);
break; break;
case 'warn': case 'warn':
if (hasPermForChannel(await getOwnMemberInServer(message.channel!.server!), message.channel!, 'SendMessage')) if (member.hasPermission(message.channel!, 'SendMessage'))
await custom_warn(message, action); await custom_warn(message, action);
else else
logger.warn(`Custom rule ${rule._id}: 'warn' action lacks permission`); logger.warn(`Custom rule ${rule._id}: 'warn' action lacks permission`);
break; break;
default: default:
logger.warn(`Unknown action ${action.action} in custom rule ${rule._id} in server ${message.channel?.server_id}`); logger.warn(`Unknown action ${action.action} in custom rule ${rule._id} in server ${message.channel?.serverId}`);
} }
} }
} }

View file

@ -1,4 +1,4 @@
import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { Message } from "revolt.js";
import { client } from "../../.."; import { client } from "../../..";
import CustomRuleTrigger from "automod/dist/types/antispam/CustomRuleTrigger"; import CustomRuleTrigger from "automod/dist/types/antispam/CustomRuleTrigger";
import VM from 'vm'; import VM from 'vm';
@ -12,8 +12,8 @@ async function messageContentTrigger(message: Message, trigger: CustomRuleTrigge
let matched = false; let matched = false;
if (trigger.matcher) { if (trigger.matcher) {
if (trigger.channelFilter) { if (trigger.channelFilter) {
if (trigger.channelFilter.mode == 'WHITELIST' && !trigger.channelFilter.channels.includes(message.channel_id)) return false; if (trigger.channelFilter.mode == 'WHITELIST' && !trigger.channelFilter.channels.includes(message.channelId)) return false;
if (trigger.channelFilter.mode == 'BLACKLIST' && trigger.channelFilter.channels.includes(message.channel_id)) return false; if (trigger.channelFilter.mode == 'BLACKLIST' && trigger.channelFilter.channels.includes(message.channelId)) return false;
} }
if (trigger.matcher instanceof RegExp) { if (trigger.matcher instanceof RegExp) {
@ -55,8 +55,8 @@ async function messageContentTrigger(message: Message, trigger: CustomRuleTrigge
let timeoutKeys = { let timeoutKeys = {
global: trigger._id, global: trigger._id,
channel: trigger._id + '/channel/' + message.channel_id, channel: trigger._id + '/channel/' + message.channelId,
user: trigger._id + '/user/' + message.author_id, user: trigger._id + '/user/' + message.authorId,
} }
let timeoutPass = true; let timeoutPass = true;
@ -87,7 +87,7 @@ async function messageContentTrigger(message: Message, trigger: CustomRuleTrigge
/* User/bot filter comes last because we want to avoid fetching users if possible */ /* User/bot filter comes last because we want to avoid fetching users if possible */
if (trigger.userFilter && trigger.userFilter != 'any') { if (trigger.userFilter && trigger.userFilter != 'any') {
let user = message.author || await client.users.fetch(message.author_id); let user = message.author || await client.users.fetch(message.authorId!);
if (trigger.userFilter == 'bot' && !user.bot) return false; if (trigger.userFilter == 'bot' && !user.bot) return false;
if (trigger.userFilter == 'user' && user.bot) return false; if (trigger.userFilter == 'user' && user.bot) return false;
} }

View file

@ -5,71 +5,61 @@ import Infraction from "automod/dist/types/antispam/Infraction";
import InfractionType from "automod/dist/types/antispam/InfractionType"; import InfractionType from "automod/dist/types/antispam/InfractionType";
import { BLACKLIST_BAN_REASON, BLACKLIST_MESSAGE } from "../commands/admin/botadm"; import { BLACKLIST_BAN_REASON, BLACKLIST_MESSAGE } from "../commands/admin/botadm";
import logger from "../logger"; import logger from "../logger";
import { hasPermForChannel, storeInfraction } from "../util"; import { storeInfraction } from "../util";
import { DEFAULT_PREFIX } from "./command_handler"; import { DEFAULT_PREFIX } from "./command_handler";
import { SendableEmbed } from "revolt-api";
const DM_SESSION_LIFETIME = 1000 * 60 * 60 * 24 * 30; const DM_SESSION_LIFETIME = 1000 * 60 * 60 * 24 * 30;
// Listen to system messages // Listen to system messages
client.on('message', async message => { client.on('messageCreate', async message => {
if (typeof message.content != 'object') {
// reply to 74
if (message.author_id == '01FCXF8V6RDKHSQ3AHJ410AASX' && message.content == 'we do a little') {
try {
message.reply('shut the fuck up');
} catch(e) { console.error(e) }
}
return; let sysMsg = message.systemMessage;
}
let sysMsg = message.asSystemMessage; if (sysMsg) switch(sysMsg.type) {
switch(sysMsg.type) {
case 'user_kicked': case 'user_kicked':
case 'user_banned': case 'user_banned':
try { try {
let recentEvents = await dbs.INFRACTIONS.findOne({ let recentEvents = await dbs.INFRACTIONS.findOne({
date: { $gt: Date.now() - 30000 }, date: { $gt: Date.now() - 30000 },
user: sysMsg.user?._id, user: sysMsg.id,
server: message.channel!.server_id!, server: message.channel!.serverId!,
actionType: sysMsg.type == 'user_kicked' ? 'kick' : 'ban', actionType: sysMsg.type == 'user_kicked' ? 'kick' : 'ban',
}); });
if (!message.channel || if (!message.channel ||
!sysMsg.user || !sysMsg.id ||
recentEvents) return; recentEvents) return;
storeInfraction({ storeInfraction({
_id: ulid(), _id: ulid(),
createdBy: sysMsg.by?._id, createdBy: null,
reason: 'Unknown reason (caught system message)', reason: 'Unknown reason (caught system message)',
date: message.createdAt, date: message.createdAt.getTime(),
server: message.channel!.server_id, server: message.channel!.serverId,
type: InfractionType.Manual, type: InfractionType.Manual,
user: sysMsg.user!._id, user: sysMsg.id,
actionType: sysMsg.type == 'user_kicked' ? 'kick' : 'ban', actionType: sysMsg.type == 'user_kicked' ? 'kick' : 'ban',
} as Infraction).catch(console.warn); } as Infraction).catch(console.warn);
} catch(e) { console.error(e) } } catch(e) { console.error(e) }
break; break;
case 'user_joined': { case 'user_joined': {
if (!sysMsg.user) break;
try { try {
const [ serverConfig, userConfig ] = await Promise.all([ const [ serverConfig, userConfig ] = await Promise.all([
dbs.SERVERS.findOne({ id: message.channel!.server_id! }), dbs.SERVERS.findOne({ id: message.channel!.serverId }),
dbs.USERS.findOne({ id: sysMsg.user._id }), dbs.USERS.findOne({ id: sysMsg.id }),
]); ]);
if (userConfig?.globalBlacklist && !serverConfig?.allowBlacklistedUsers) { if (userConfig?.globalBlacklist && !serverConfig?.allowBlacklistedUsers) {
const server = message.channel?.server; const server = message.channel?.server;
if (server && server.havePermission('BanMembers')) { if (server && server.havePermission('BanMembers')) {
await server.banUser(sysMsg.user._id, { reason: BLACKLIST_BAN_REASON }); await server.banUser(sysMsg.id, { reason: BLACKLIST_BAN_REASON });
if (server.system_messages?.user_banned) { if (server.systemMessages?.user_banned) {
const channel = server.channels.find(c => c?._id == server.system_messages?.user_banned); const channel = server.channels.find(c => c?.id == server.systemMessages?.user_banned);
if (channel && channel.havePermission('SendMessage')) { if (channel && channel.havePermission('SendMessage')) {
await channel.sendMessage(BLACKLIST_MESSAGE(sysMsg.user.username)); const user = client.users.get(sysMsg.id);
await channel.sendMessage(BLACKLIST_MESSAGE(user?.username ?? sysMsg.id));
} }
} }
} }
@ -85,10 +75,10 @@ client.on('message', async message => {
}); });
// DM message based API session token retrieval // DM message based API session token retrieval
client.on('message', async message => { client.on('messageCreate', async message => {
try { try {
if ( if (
message.channel?.channel_type == "DirectMessage" && message.channel?.type == "DirectMessage" &&
message.nonce?.startsWith("REQUEST_SESSION_TOKEN-") && message.nonce?.startsWith("REQUEST_SESSION_TOKEN-") &&
message.content?.toLowerCase().startsWith("requesting session token.") message.content?.toLowerCase().startsWith("requesting session token.")
) { ) {
@ -97,17 +87,16 @@ client.on('message', async message => {
const token = crypto.randomBytes(48).toString('base64').replace(/=/g, ''); const token = crypto.randomBytes(48).toString('base64').replace(/=/g, '');
await client.db.get('sessions').insert({ await client.db.get('sessions').insert({
user: message.author_id, user: message.authorId,
token: token, token: token,
nonce: message.nonce, nonce: message.nonce,
invalid: false, invalid: false,
expires: Date.now() + DM_SESSION_LIFETIME, expires: Date.now() + DM_SESSION_LIFETIME,
}) })
// Don't need to risk exposing the user to the token, so we'll send it in the nonce
await message.channel.sendMessage({ await message.channel.sendMessage({
content: `Token request granted. **Do not send the content of this message to anyone!**\n$%${token}%$`, content: `Token request granted. **Do not send the content of this message to anyone!**\n$%${token}%$`,
replies: [ { id: message._id, mention: false } ], replies: [ { id: message.id, mention: false } ],
}); });
return; return;
} }
@ -117,26 +106,24 @@ client.on('message', async message => {
}); });
// Send a message when added to a server // Send a message when added to a server
client.on('member/join', (member) => { client.on('serverMemberJoin', (member) => {
if (member._id.user != client.user?._id) return; if (member.id.user != client.user?.id) return;
let url = `https://rvembed.janderedev.xyz/embed`
+ `?title=${encodeURIComponent('Hi there, thanks for adding me!')}`
+ `&description=${encodeURIComponent(`My prefix is "${DEFAULT_PREFIX}", `
+ `but you can also @mention me instead.\nCheck out ${DEFAULT_PREFIX}help to get started!`)}`
+ `&link=${encodeURIComponent(`/bot/${client.user._id}`)}`
+ `&redir=${encodeURIComponent(`https://github.com/janderedev/revolt-automod`)}`
+ `&color=${encodeURIComponent("#ff6e6d")}`
+ `&image=${encodeURIComponent(client.user.generateAvatarURL({ size: 128 }))}`
+ `&image_large=false`;
if (!member.server) return; if (!member.server) return;
const embed: SendableEmbed = {
title: 'Hi there, thanks for adding me!',
description: `My prefix is "${DEFAULT_PREFIX}", but you can also @mention me instead.\nCheck out ${DEFAULT_PREFIX}help to get started!`,
icon_url: client.user.avatarURL,
colour: '#ff6e6d',
url: `/bot/${client.user.id}`,
}
let channels = member.server.channels.filter( let channels = member.server.channels.filter(
c => c c => c
&& c.channel_type == 'TextChannel' && c.type == 'TextChannel'
&& hasPermForChannel(member, c, 'SendMessage') && member.hasPermission(c, 'SendMessage')
&& hasPermForChannel(member, c, 'SendEmbeds') && member.hasPermission(c, 'SendEmbeds')
); );
// Attempt to find an appropriate channel, otherwise use the first one available // Attempt to find an appropriate channel, otherwise use the first one available
@ -147,6 +134,8 @@ client.on('member/join', (member) => {
|| channels[0]; || channels[0];
if (!channel) return logger.debug('Cannot send hello message: No suitable channel found'); if (!channel) return logger.debug('Cannot send hello message: No suitable channel found');
channel.sendMessage(`[:wave:](${url} "Hi there!")`) channel.sendMessage({
.catch(e => logger.debug('Cannot send hello message: ' + e)); content: `:wave: "Hi there!")`,
embeds: [embed],
}).catch(e => logger.debug('Cannot send hello message: ' + e));
}); });

View file

@ -6,14 +6,14 @@ import logger from "../logger";
(async () => { (async () => {
if (!client.user) await new Promise<void>(r => client.once('ready', () => r())); if (!client.user) await new Promise<void>(r => client.once('ready', () => r()));
logger.info(`Starting to fetch users in ${client.servers.size} servers.`); logger.info(`Starting to fetch users in ${client.servers.size()} servers.`);
const promises: Promise<any>[] = []; const promises: Promise<any>[] = [];
for (const server of client.servers) { for (const server of client.servers.entries()) {
promises.push(server[1].fetchMembers()); promises.push(server[1].fetchMembers());
} }
const res = await Promise.allSettled(promises); const res = await Promise.allSettled(promises);
logger.done(`Downloaded all users from ${res.filter(r => r.status == 'fulfilled').length} servers ` logger.done(`Downloaded all users from ${res.filter(r => r.status == 'fulfilled').length} servers `
+ `with ${res.filter(r => r.status == 'rejected').length} errors. Cache size: ${client.users.size}`); + `with ${res.filter(r => r.status == 'rejected').length} errors. Cache size: ${client.users.size()}`);
})(); })();

View file

@ -30,14 +30,14 @@ if (!isNaN(PORT)) {
} }
}); });
const setServerCount = () => metrics.servers.set(client.servers.size); const setServerCount = () => metrics.servers.set(client.servers.size());
client.once('ready', setServerCount); client.once('ready', setServerCount);
client.on('server/update', setServerCount); client.on('serverUpdate', setServerCount);
client.on('server/delete', setServerCount); client.on('serverDelete', setServerCount);
const measureLatency = async () => { const measureLatency = async () => {
const wsPing = client.websocket.ping; const wsPing = -1; // currently not exported by revolt.js, todo?
if (wsPing != undefined) metrics.wsPing.set(wsPing); if (wsPing != undefined) metrics.wsPing.set(wsPing);
} }

View file

@ -1,49 +1,46 @@
import { Member } from "@janderedev/revolt.js/dist/maps/Members"; import { Server, ServerMember } from "revolt.js";
import { Server } from "@janderedev/revolt.js/dist/maps/Servers";
import { client, dbs } from "../.."; import { client, dbs } from "../..";
import LogMessage from "automod/dist/types/LogMessage"; import LogMessage from "automod/dist/types/LogMessage";
import Xlsx from 'xlsx';
import logger from "../logger"; import logger from "../logger";
import { getAutumnURL, sanitizeMessageContent, sendLogMessage } from "../util"; import { sanitizeMessageContent, sendLogMessage } from "../util";
// the `packet` event is emitted before the client's cache // the `packet` event is emitted before the client's cache
// is updated, which allows us to get the old message content // is updated, which allows us to get the old message content
// if it was cached before // if it was cached before
client.on('packet', async (packet) => { client.on('messageUpdate', async (message, oldMessage) => {
if (packet.type == 'MessageUpdate') {
try { try {
if (!packet.data.content) return; if (!message.content) return;
let m = client.messages.get(packet.id); if (message.authorId == client.user?.id) return;
if (m?.author_id == client.user?._id) return; let oldMsgRaw = String(oldMessage.content ?? '(Unknown)');
let newMsgRaw = String(message.content);
let oldMsgRaw = String(m?.content ?? '(Unknown)');
let newMsgRaw = String(packet.data.content);
let oldMsg = sanitizeMessageContent(oldMsgRaw) || '(Empty)'; let oldMsg = sanitizeMessageContent(oldMsgRaw) || '(Empty)';
let newMsg = sanitizeMessageContent(newMsgRaw) || '(Empty)'; let newMsg = sanitizeMessageContent(newMsgRaw) || '(Empty)';
let channel = client.channels.get(packet.channel); let channel = message.channel;
let server = channel?.server; let server = channel?.server;
if (!server || !channel) return logger.warn('Received message update in unknown channel or server'); if (!server || !channel) return logger.warn('Received message update in unknown channel or server');
let config = await dbs.SERVERS.findOne({ id: server._id }); let config = await dbs.SERVERS.findOne({ id: server.id });
if (config?.logs?.messageUpdate) { if (config?.logs?.messageUpdate) {
const attachFullMessage = oldMsg.length > 800 || newMsg.length > 800; const attachFullMessage = oldMsg.length > 800 || newMsg.length > 800;
let embed: LogMessage = { let embed: LogMessage = {
title: `Message edited in ${server.name}`, title: `Message edited in ${server.name}`,
description: description:
`[#${channel.name}](/server/${server._id}/channel/${channel._id}) | ` + `[#${channel.name}](/server/${server.id}/channel/${channel.id}) | ` +
`[@${sanitizeMessageContent( `@${sanitizeMessageContent(
m?.author?.username ?? "Unknown User" message.author?.username ?? "Unknown User"
)}](/@${m?.author_id}) | ` + )} (${message.authorId}) | ` +
`[Jump to message](/server/${server._id}/channel/${channel._id}/${packet.id})`, `[Jump to message](/server/${server.id}/channel/${channel.id}/${message.id})`,
fields: [], fields: [],
color: "#829dff", color: "#829dff",
overrides: { overrides: {
discord: { discord: {
description: `Author: @${ description: `Author: @${
m?.author?.username || m?.author_id || "Unknown" message.author?.username || message.authorId || "Unknown"
} | Channel: ${channel?.name || channel?._id}`, } | Channel: ${channel.name || channel.id}`,
}, },
}, },
}; };
@ -63,30 +60,30 @@ client.on('packet', async (packet) => {
} catch(e) { } catch(e) {
console.error(e); console.error(e);
} }
} });
client.on('messageDelete', async (message) => {
if (packet.type == 'MessageDelete') {
try { try {
let channel = client.channels.get(packet.channel); let channel = client.channels.get(message.channelId);
let author = message.authorId ? client.users.get(message.authorId) : null;
if (!channel) return; if (!channel) return;
let message = client.messages.get(packet.id);
if (!message) return;
let msgRaw = String(message.content ?? '(Unknown)'); let msgRaw = String(message.content ?? '(Unknown)');
let msg = sanitizeMessageContent(msgRaw); let msg = sanitizeMessageContent(msgRaw);
let config = await dbs.SERVERS.findOne({ id: message.channel?.server?._id }); let config = await dbs.SERVERS.findOne({ id: channel?.server?.id });
if (config?.logs?.messageUpdate) { if (config?.logs?.messageUpdate) {
let embed: LogMessage = { let embed: LogMessage = {
title: `Message deleted in ${message.channel?.server?.name}`, title: `Message deleted in ${channel?.server?.name}`,
description: `[\\[#${channel.name}\\]](/server/${channel.server_id}/channel/${channel._id}) | ` description: `[#${channel.name}](/server/${channel.serverId}/channel/${channel.id}) | `
+ `[\\[Author\\]](/@${message.author_id}) | ` + `@${sanitizeMessageContent(
+ `[\\[Jump to context\\]](/server/${channel.server_id}/channel/${channel._id}/${packet.id})`, author?.username ?? "Unknown User"
)} (${message.authorId}) | `
+ `[\\[Jump to context\\]](/server/${channel.serverId}/channel/${channel.id}/${message.id})`,
fields: [], fields: [],
color: '#ff6b6b', color: '#ff6b6b',
overrides: { overrides: {
discord: { discord: {
description: `Author: @${message.author?.username || message.author_id} | Channel: ${message.channel?.name || message.channel_id}` description: `Author: @${author?.username || message.authorId} | Channel: ${channel?.name || message.channelId}`
}, },
} }
} }
@ -98,9 +95,9 @@ client.on('packet', async (packet) => {
} }
if (message.attachments?.length) { if (message.attachments?.length) {
let autumnURL = await getAutumnURL(); let autumnURL = client.configuration?.features.autumn.url;
embed.fields!.push({ title: 'Attachments', content: message.attachments.map(a => embed.fields!.push({ title: 'Attachments', content: message.attachments.map(a =>
`[\\[${a.filename}\\]](<${autumnURL}/${a.tag}/${a._id}/${a.filename}>)`).join(' | ') }) `[\\[${a.filename}\\]](<${autumnURL}/${a.tag}/${a.id}/${a.filename}>)`).join(' | ') })
} }
await sendLogMessage(config.logs.messageUpdate, embed); await sendLogMessage(config.logs.messageUpdate, embed);
@ -108,39 +105,57 @@ client.on('packet', async (packet) => {
} catch(e) { } catch(e) {
console.error(e); console.error(e);
} }
}
if (packet.type == 'BulkMessageDelete') {
const channel = client.channels.get(packet.channel);
if (!channel) return;
try {
let config = await dbs.SERVERS.findOne({ id: channel.server?._id });
if (config?.logs?.messageUpdate) {
let embed: LogMessage = {
title: `Bulk delete in ${channel.server?.name}`,
description: `${packet.ids.length} messages deleted in ` +
`[#${channel.name}](/server/${channel.server_id}/channel/${channel._id})`,
fields: [],
color: '#ff392b',
overrides: {
discord: {
description: `${packet.ids.length} messages deleted in #${channel.name}`,
}
}
}
await sendLogMessage(config.logs.messageUpdate, embed);
}
} catch(e) {
console.error(e);
}
}
}); });
async function logModAction(type: 'warn'|'kick'|'ban'|'votekick', server: Server, mod: Member, target: string, reason: string|null, infractionID: string, extraText?: string): Promise<void> { client.on('messageDeleteBulk', async (messages) => {
const channel = client.channels.get(messages[0].channelId);
if (!channel) return;
try { try {
let config = await dbs.SERVERS.findOne({ id: server._id }); let config = await dbs.SERVERS.findOne({ id: channel.serverId });
if (config?.logs?.messageUpdate) {
const data: String[][] = [
['Message ID', 'Author ID', 'Author Name', 'Content', 'Attachment URLs'],
[],
];
for (const message of messages) {
data.push([
message.id,
message.authorId ?? '',
message.authorId ? client.users.get(message.authorId)?.username ?? '' : '',
message.content ?? '',
message.attachments?.map(a => a.id).join(', ') ?? '',
]);
}
const sheet = Xlsx.utils.aoa_to_sheet(data);
const csv = Xlsx.utils.sheet_to_csv(data);
let embed: LogMessage = {
title: `Bulk delete in ${channel.server?.name}`,
description: `${messages.length} messages deleted in ` +
`[#${channel.name}](/server/${channel.serverId}/channel/${channel.id})`,
fields: [],
attachments: [{ name: 'messages.csv', content: Buffer.from(csv) }],
color: '#ff392b',
overrides: {
discord: {
description: `${messages.length} messages deleted in #${channel.name}`,
}
}
}
await sendLogMessage(config.logs.messageUpdate, embed);
}
} catch(e) {
console.error(e);
}
});
async function logModAction(type: 'warn'|'kick'|'ban'|'votekick', server: Server, mod: ServerMember, target: string, reason: string|null, infractionID: string, extraText?: string): Promise<void> {
try {
let config = await dbs.SERVERS.findOne({ id: server.id });
if (config?.logs?.modAction) { if (config?.logs?.modAction) {
let aType = type == 'ban' ? 'banned' : type + 'ed'; let aType = type == 'ban' ? 'banned' : type + 'ed';

View file

@ -29,11 +29,11 @@ async function processUnban(ban: TempBan) {
if (expired.includes(ban.id)) return; if (expired.includes(ban.id)) return;
let server = client.servers.get(ban.server) || await client.servers.fetch(ban.server); let server = client.servers.get(ban.server) || await client.servers.fetch(ban.server);
if (!server.havePermission('BanMembers')) return logger.debug(`No permission to process unbans in ${server._id}, skipping`); if (!server.havePermission('BanMembers')) return logger.debug(`No permission to process unbans in ${server.id}, skipping`);
let serverBans = await server.fetchBans(); let serverBans = await server.fetchBans();
if (serverBans.bans.find(b => b._id.user == ban.bannedUser)) { if (serverBans.find(b => b.id.user == ban.bannedUser)) {
logger.debug(`Unbanning user ${ban.bannedUser} from ${server._id}`); logger.debug(`Unbanning user ${ban.bannedUser} from ${server.id}`);
let promises = [ let promises = [
server.unbanUser(ban.bannedUser), server.unbanUser(ban.bannedUser),

View file

@ -1,23 +1,20 @@
import { Member } from "@janderedev/revolt.js/dist/maps/Members"; import { ServerMember } from "revolt.js";
import { User } from "@janderedev/revolt.js/dist/maps/Users"; import { User } from "revolt.js";
import { client, dbs } from ".."; import { client, dbs } from "..";
import Infraction from "automod/dist/types/antispam/Infraction"; import Infraction from "automod/dist/types/antispam/Infraction";
import FormData from 'form-data'; import FormData from 'form-data';
import axios from 'axios'; import axios from 'axios';
import { Server } from "@janderedev/revolt.js/dist/maps/Servers"; import { Server } from "revolt.js";
import LogConfig from "automod/dist/types/LogConfig"; import LogConfig from "automod/dist/types/LogConfig";
import LogMessage from "automod/dist/types/LogMessage"; import LogMessage from "automod/dist/types/LogMessage";
import { ColorResolvable, MessageEmbed } from "discord.js"; import { ColorResolvable, MessageEmbed } from "discord.js";
import logger from "./logger"; import logger from "./logger";
import { ulid } from "ulid"; import { ulid } from "ulid";
import { Channel } from "@janderedev/revolt.js/dist/maps/Channels"; import { Channel } from "revolt.js";
import { Permission } from "@janderedev/revolt.js/dist/permissions/definitions"; import { Message } from "revolt.js";
import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { isSudo } from "./commands/admin/botadm"; import { isSudo } from "./commands/admin/botadm";
import { SendableEmbed } from "revolt-api"; import { SendableEmbed } from "revolt-api";
import MessageCommandContext from "../struct/MessageCommandContext";
import ServerConfig from "automod/dist/types/ServerConfig"; import ServerConfig from "automod/dist/types/ServerConfig";
import { ClientboundNotification } from "@janderedev/revolt.js";
const NO_MANAGER_MSG = "🔒 Missing permission"; const NO_MANAGER_MSG = "🔒 Missing permission";
const ULID_REGEX = /^[0-9A-HJ-KM-NP-TV-Z]{26}$/i; const ULID_REGEX = /^[0-9A-HJ-KM-NP-TV-Z]{26}$/i;
@ -26,18 +23,6 @@ const CHANNEL_MENTION_REGEX = /^<#[0-9A-HJ-KM-NP-TV-Z]{26}>$/i;
const RE_HTTP_URI = /^http(s?):\/\//g; const RE_HTTP_URI = /^http(s?):\/\//g;
const RE_MAILTO_URI = /^mailto:/g; const RE_MAILTO_URI = /^mailto:/g;
let autumn_url: string | null = null;
let apiConfig: any = axios.get(client.apiURL).then((res) => {
autumn_url = (res.data as any).features.autumn.url;
});
async function getAutumnURL() {
return (
autumn_url ||
((await axios.get(client.apiURL)).data as any).features.autumn.url
);
}
/** /**
* Parses user input and returns an user object. * Parses user input and returns an user object.
* Supports: `userID`, `<@userID>` (mention), `username`, `@username` (if user is cached). * Supports: `userID`, `<@userID>` (mention), `username`, `@username` (if user is cached).
@ -80,10 +65,10 @@ async function parseUser(text: string): Promise<User | null> {
*/ */
async function parseUserOrId( async function parseUserOrId(
text: string text: string
): Promise<User | { _id: string } | null> { ): Promise<User | { id: string } | null> {
let parsed = await parseUser(text); let parsed = await parseUser(text);
if (parsed) return parsed; if (parsed) return parsed;
if (ULID_REGEX.test(text)) return { _id: text.toUpperCase() }; if (ULID_REGEX.test(text)) return { id: text.toUpperCase() };
return null; return null;
} }
@ -91,17 +76,17 @@ async function isModerator(message: Message, announceSudo?: boolean) {
let member = message.member!, let member = message.member!,
server = message.channel!.server!; server = message.channel!.server!;
if (hasPerm(member, "KickMembers")) return true; if (member.hasPermission(member.server!, "KickMembers")) return true;
const [isManager, mods, isSudo] = await Promise.all([ const [isManager, mods, isSudo] = await Promise.all([
isBotManager(message), isBotManager(message),
dbs.SERVERS.findOne({ id: server._id }), dbs.SERVERS.findOne({ id: server.id }),
checkSudoPermission(message, announceSudo), checkSudoPermission(message, announceSudo),
]); ]);
return ( return (
isManager || isManager ||
(mods?.moderators?.indexOf(member.user?._id!) ?? -1) > -1 || (mods?.moderators?.indexOf(member.user?.id!) ?? -1) > -1 ||
isSudo isSudo
); );
} }
@ -109,15 +94,15 @@ async function isBotManager(message: Message, announceSudo?: boolean) {
let member = message.member!, let member = message.member!,
server = message.channel!.server!; server = message.channel!.server!;
if (hasPerm(member, "ManageServer")) return true; if (member.hasPermission(member.server!, "ManageServer")) return true;
const [managers, isSudo] = await Promise.all([ const [managers, isSudo] = await Promise.all([
dbs.SERVERS.findOne({ id: server._id }), dbs.SERVERS.findOne({ id: server.id }),
checkSudoPermission(message, announceSudo), checkSudoPermission(message, announceSudo),
]); ]);
return ( return (
(managers?.botManagers?.indexOf(member.user?._id!) ?? -1) > -1 || isSudo (managers?.botManagers?.indexOf(member.user?.id!) ?? -1) > -1 || isSudo
); );
} }
async function checkSudoPermission( async function checkSudoPermission(
@ -137,68 +122,38 @@ async function checkSudoPermission(
} }
} }
async function getPermissionLevel( async function getPermissionLevel(
user: User | Member, member: ServerMember | User,
server: Server server: Server
): Promise<0 | 1 | 2 | 3> { ): Promise<0 | 1 | 2 | 3> {
if (member instanceof User) {
member = client.serverMembers.getByKey({ server: server.id, user: member.id }) || await server.fetchMember(member.id);
}
if (isSudo(member.user!)) return 3;
if (member.hasPermission(member.server!, "ManageServer")) return 3;
const config = await dbs.SERVERS.findOne({ id: server.id });
if (config?.botManagers?.includes(member.id.user)) return 2;
if ( if (
isSudo( config?.moderators?.includes(member.id.user) ||
user instanceof User member.hasPermission(member.server!, "KickMembers")
? user
: user.user || (await client.users.fetch(user._id.user))
)
)
return 3;
const member = user instanceof User ? await server.fetchMember(user) : user;
if (user instanceof Member) user = user.user!;
if (hasPerm(member, "ManageServer")) return 3;
const config = await dbs.SERVERS.findOne({ id: server._id });
if (config?.botManagers?.includes(user._id)) return 2;
if (
config?.moderators?.includes(user._id) ||
hasPerm(member, "KickMembers")
) )
return 1; return 1;
return 0; return 0;
} }
function getPermissionBasedOnRole(member: Member): 0 | 1 | 2 | 3 { function getPermissionBasedOnRole(member: ServerMember): 0 | 1 | 2 | 3 {
if (hasPerm(member, "ManageServer")) return 3; if (member.hasPermission(member.server!, "ManageServer")) return 3;
if (hasPerm(member, "KickMembers")) return 1; if (member.hasPermission(member.server!, "KickMembers")) return 1;
return 0; return 0;
} }
/** async function getOwnMemberInServer(server: Server): Promise<ServerMember> {
* @deprecated Unnecessary return server.member || await server.fetchMember(client.user!.id);
*/
function hasPerm(member: Member, perm: keyof typeof Permission): boolean {
let p = Permission[perm];
if (member.server?.owner == member.user?._id) return true;
return member.hasPermission(member.server!, perm);
}
/**
* @deprecated Unnecessary
*/
function hasPermForChannel(
member: Member,
channel: Channel,
perm: keyof typeof Permission
): boolean {
if (!member.server) throw "hasPermForChannel(): Server is undefined";
return member.hasPermission(channel, perm);
}
async function getOwnMemberInServer(server: Server): Promise<Member> {
return (
client.members.getKey({ server: server._id, user: client.user!._id }) ||
(await server.fetchMember(client.user!._id))
);
} }
async function storeInfraction( async function storeInfraction(
@ -220,7 +175,7 @@ async function uploadFile(file: any, filename: string): Promise<string> {
let data = new FormData(); let data = new FormData();
data.append("file", file, { filename: filename }); data.append("file", file, { filename: filename });
let req = await axios.post((await getAutumnURL()) + "/attachments", data, { let req = await axios.post(client.configuration?.features.autumn.url + "/attachments", data, {
headers: data.getHeaders(), headers: data.getHeaders(),
}); });
return (req.data as any)["id"] as string; return (req.data as any)["id"] as string;
@ -432,8 +387,8 @@ function dedupeArray<T>(...arrays: T[][]): T[] {
function getMutualServers(user: User) { function getMutualServers(user: User) {
const servers: Server[] = []; const servers: Server[] = [];
for (const member of client.members) { for (const member of client.serverMembers.entries()) {
if (member[1]._id.user == user._id && member[1].server) if (member[1].id.user == user.id && member[1].server)
servers.push(member[1].server); servers.push(member[1].server);
} }
return servers; return servers;
@ -445,19 +400,21 @@ const awaitClient = () =>
else resolve(); else resolve();
}); });
const getDmChannel = async (user: string | { _id: string } | User) => { const getDmChannel = async (user: string | { id: string } | User) => {
if (typeof user == "string") if (typeof user == "string") {
user = client.users.get(user) || (await client.users.fetch(user)); user = client.users.get(user) || (await client.users.fetch(user));
if (!(user instanceof User)) }
user =
client.users.get(user._id) || (await client.users.fetch(user._id)); if (!(user instanceof User)) {
user = client.users.get(user.id) || (await client.users.fetch(user.id));
}
return ( return (
Array.from(client.channels).find( Array.from(client.channels.values()).find(
(c) => (c: Channel) =>
c[1].channel_type == "DirectMessage" && c.type == "DirectMessage" &&
c[1].recipient?._id == (user as User)._id c.recipient?.id == (user as User).id
)?.[1] || (await (user as User).openDM()) ) || (await (user as User).openDM())
); );
}; };
@ -469,7 +426,7 @@ const generateInfractionDMEmbed = (
) => { ) => {
const embed: SendableEmbed = { const embed: SendableEmbed = {
title: server.name, title: server.name,
icon_url: server.generateIconURL({ max_side: 128 }), icon_url: server.icon?.createFileURL({ max_side: 128 }),
colour: "#ff9e2f", colour: "#ff9e2f",
url: message.url, url: message.url,
description: description:
@ -485,7 +442,7 @@ const generateInfractionDMEmbed = (
`**Reason:** ${infraction.reason}\n` + `**Reason:** ${infraction.reason}\n` +
`**Moderator:** [@${sanitizeMessageContent( `**Moderator:** [@${sanitizeMessageContent(
message.author?.username || "Unknown" message.author?.username || "Unknown"
)}](/@${message.author_id})\n` + )}](/@${message.authorId})\n` +
`**Infraction ID:** \`${infraction._id}\`` + `**Infraction ID:** \`${infraction._id}\`` +
(infraction.actionType == "ban" && infraction.expires (infraction.actionType == "ban" && infraction.expires
? infraction.expires == Infinity ? infraction.expires == Infinity
@ -545,14 +502,13 @@ const yesNoMessage = (
}); });
let destroyed = false; let destroyed = false;
const cb = async (packet: ClientboundNotification) => { const cb = async (m: Message, userId: string, emoji: string) => {
if (packet.type != "MessageReact") return; if (m.id != msg.id) return;
if (packet.id != msg._id) return; if (userId != allowedUser) return;
if (packet.user_id != allowedUser) return;
switch (packet.emoji_id) { switch (emoji) {
case EMOJI_YES: case EMOJI_YES:
channel.client.removeListener("packet", cb); client.removeListener("messageReactionAdd", cb);
destroyed = true; destroyed = true;
resolve(true); resolve(true);
msg.edit({ msg.edit({
@ -569,7 +525,7 @@ const yesNoMessage = (
break; break;
case EMOJI_NO: case EMOJI_NO:
channel.client.removeListener("packet", cb); client.removeListener("messageReactionAdd", cb);
destroyed = true; destroyed = true;
resolve(false); resolve(false);
msg.edit({ msg.edit({
@ -587,16 +543,16 @@ const yesNoMessage = (
default: default:
logger.warn( logger.warn(
"Received unexpected reaction: " + packet.emoji_id "Received unexpected reaction: " + emoji
); );
} }
}; };
channel.client.on("packet", cb); client.on("messageReactionAdd", cb);
setTimeout(() => { setTimeout(() => {
if (!destroyed) { if (!destroyed) {
resolve(false); resolve(false);
channel.client.removeListener("packet", cb); client.removeListener("messageReactionAdd", cb);
msg.edit({ msg.edit({
embeds: [ embeds: [
{ {
@ -615,14 +571,19 @@ const yesNoMessage = (
// Get all cached members of a server. Whoever put STRINGIFIED JSON as map keys is now on my hit list. // Get all cached members of a server. Whoever put STRINGIFIED JSON as map keys is now on my hit list.
const getMembers = (id: string) => const getMembers = (id: string) =>
Array.from(client.members.entries()) Array.from(client.serverMembers.entries())
.filter((item) => item[0].includes(`"${id}"`)) .filter((item) => item[0].includes(`"${id}"`))
.map((entry) => entry[1]); .map((entry) => entry[1]);
const memberRanking = (member: ServerMember) => {
const inferior = (member.server?.member?.ranking ?? Infinity) < member.ranking;
const kickable = member.server?.havePermission('KickMembers') && inferior;
const bannable = member.server?.havePermission('BanMembers') && inferior;
return { inferior, kickable, bannable }
}
export { export {
getAutumnURL,
hasPerm,
hasPermForChannel,
getOwnMemberInServer, getOwnMemberInServer,
isModerator, isModerator,
isBotManager, isBotManager,
@ -642,6 +603,7 @@ export {
generateInfractionDMEmbed, generateInfractionDMEmbed,
yesNoMessage, yesNoMessage,
getMembers, getMembers,
memberRanking,
EmbedColor, EmbedColor,
NO_MANAGER_MSG, NO_MANAGER_MSG,
ULID_REGEX, ULID_REGEX,

View file

@ -18,12 +18,6 @@ logger.info('Initializing client');
let db = MongoDB(); let db = MongoDB();
let client = new AutomodClient({ let client = new AutomodClient({
// pongTimeout: 10,
// onPongTimeout: 'RECONNECT',
fixReplyCrash: true,
messageTimeoutFix: true,
apiURL: process.env.API_URL,
messageRateLimiter: true,
autoReconnect: true, autoReconnect: true,
}, db); }, db);
login(client); login(client);

View file

@ -1,12 +1,13 @@
import * as Revolt from "@janderedev/revolt.js"; import * as Revolt from "revolt.js";
import { IMonkManager } from 'monk'; import { IMonkManager } from 'monk';
import logger from '../bot/logger'; import logger from '../bot/logger';
import { adminBotLog } from "../bot/logging"; import { adminBotLog } from "../bot/logging";
import { ClientOptions } from "revolt.js/src/Client";
class AutomodClient extends Revolt.Client { class AutomodClient extends Revolt.Client {
db: IMonkManager; db: IMonkManager;
constructor(options: Partial<Revolt.ClientOptions> | undefined, monk: IMonkManager) { constructor(options: Partial<ClientOptions> | undefined, monk: IMonkManager) {
super(options); super(options);
this.db = monk; this.db = monk;
@ -29,13 +30,6 @@ let login = (client: Revolt.Client): Promise<void> => new Promise((resolve, reje
adminBotLog({ message: 'Bot logged in', type: 'INFO' }); adminBotLog({ message: 'Bot logged in', type: 'INFO' });
resolve(); resolve();
}); });
client.on('packet', packet => {
if (packet.type == 'InvalidSession' as any) {
logger.error('Authentication failed: ' + JSON.stringify(packet));
process.exit(99);
}
});
}); });
export default AutomodClient; export default AutomodClient;

View file

@ -1,14 +1,9 @@
import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { Message } from "revolt.js";
import { Server } from "@janderedev/revolt.js/dist/maps/Servers"; import { Server } from "revolt.js";
import logger from "../bot/logger";
class MessageCommandContext extends Message { class MessageCommandContext extends Message {
// The server to which the command should be applied. // The server to which the command should be applied.
serverContext: Server; serverContext: Server;
/* Override types */
declare content: string;
} }
export default MessageCommandContext; export default MessageCommandContext;

View file

@ -25,22 +25,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@insertish/exponential-backoff@npm:3.1.0-patch.2":
version: 3.1.0-patch.2
resolution: "@insertish/exponential-backoff@npm:3.1.0-patch.2"
checksum: 510a531965965c8cc633a91653ca09ffa8408925eb403d07c072bed065ec8ce429b4fd42fb0639a3dbee73d300d4422c306ebaaab3292b06778a224a2b5b0bf1
languageName: node
linkType: hard
"@insertish/isomorphic-ws@npm:^4.0.1":
version: 4.0.1
resolution: "@insertish/isomorphic-ws@npm:4.0.1"
peerDependencies:
ws: "*"
checksum: 64e6464b379784d0c8df31868eb8301b3e3827f91131755c38f66a007fcd791314c6ef49f3ead37bb5d62cc7fd52f2171b2e0ce04564a744905f72d3cd86f1ba
languageName: node
linkType: hard
"@insertish/oapi@npm:0.1.18": "@insertish/oapi@npm:0.1.18":
version: 0.1.18 version: 0.1.18
resolution: "@insertish/oapi@npm:0.1.18" resolution: "@insertish/oapi@npm:0.1.18"
@ -59,26 +43,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@janderedev/revolt.js@npm:latest":
version: 6.0.20-patch.9
resolution: "@janderedev/revolt.js@npm:6.0.20-patch.9"
dependencies:
"@insertish/exponential-backoff": 3.1.0-patch.2
"@insertish/isomorphic-ws": ^4.0.1
axios: ^0.21.4
eventemitter3: ^4.0.7
lodash.defaultsdeep: ^4.6.1
lodash.flatten: ^4.4.0
lodash.isequal: ^4.5.0
long: ^5.2.0
mobx: ^6.3.2
revolt-api: 0.5.16
ulid: ^2.3.0
ws: ^8.2.2
checksum: 942f8cb7339f6378738d97ff788680dc63c287624e749b95b867a82c877bc6416a4a7b85264bf8797e034132d5a84843d75b820b6a1c37a760a88f13114772a0
languageName: node
linkType: hard
"@sapphire/async-queue@npm:^1.5.0": "@sapphire/async-queue@npm:^1.5.0":
version: 1.5.0 version: 1.5.0
resolution: "@sapphire/async-queue@npm:1.5.0" resolution: "@sapphire/async-queue@npm:1.5.0"
@ -96,6 +60,48 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@solid-primitives/map@npm:^0.4.3":
version: 0.4.3
resolution: "@solid-primitives/map@npm:0.4.3"
dependencies:
"@solid-primitives/trigger": ^1.0.3
peerDependencies:
solid-js: ^1.6.12
checksum: e2408d7309c2bc0b93126771ad796cc3cbc2b150a03b4f3d4963dbc6df2ad26e671277fc14aafe1c117f1228c35557686e709accd6237ac511d2e05a6682006d
languageName: node
linkType: hard
"@solid-primitives/set@npm:^0.4.3":
version: 0.4.3
resolution: "@solid-primitives/set@npm:0.4.3"
dependencies:
"@solid-primitives/trigger": ^1.0.3
peerDependencies:
solid-js: ^1.6.12
checksum: fcab5679185633b887d6d9ef4c12ded12d1773969a66079ce98dc18bbb2869f9fe743a1f3cd1f5721b52dcd274ae096470daa8ab1284643b4b26eeb28b7a5698
languageName: node
linkType: hard
"@solid-primitives/trigger@npm:^1.0.3":
version: 1.0.5
resolution: "@solid-primitives/trigger@npm:1.0.5"
dependencies:
"@solid-primitives/utils": ^6.0.0
peerDependencies:
solid-js: ^1.6.12
checksum: 5f137ec425b317c09de6b994928992201206c16be7a01f7add46e0ee987d76a947a7f4f9396a945eeb671c43307b6f5d55bd57d90738880cebdaa0907aca65dd
languageName: node
linkType: hard
"@solid-primitives/utils@npm:^6.0.0":
version: 6.0.0
resolution: "@solid-primitives/utils@npm:6.0.0"
peerDependencies:
solid-js: ^1.6.12
checksum: c581b995e2d16c9ed0546baef52a9e60f54dda457a3733bac467a19f2a63227179eb0ec6faa16397af4cacc13fa281288cf967a206b0a75255412fafadc55411
languageName: node
linkType: hard
"@types/bson@npm:*": "@types/bson@npm:*":
version: 4.0.5 version: 4.0.5
resolution: "@types/bson@npm:4.0.5" resolution: "@types/bson@npm:4.0.5"
@ -196,15 +202,6 @@ __metadata:
languageName: node languageName: node
linkType: soft linkType: soft
"axios@npm:^0.21.4":
version: 0.21.4
resolution: "axios@npm:0.21.4"
dependencies:
follow-redirects: ^1.14.0
checksum: 44245f24ac971e7458f3120c92f9d66d1fc695e8b97019139de5b0cc65d9b8104647db01e5f46917728edfc0cfd88eb30fc4c55e6053eef4ace76768ce95ff3c
languageName: node
linkType: hard
"axios@npm:^0.22.0": "axios@npm:^0.22.0":
version: 0.22.0 version: 0.22.0
resolution: "axios@npm:0.22.0" resolution: "axios@npm:0.22.0"
@ -298,6 +295,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"csstype@npm:^3.1.0":
version: 3.1.2
resolution: "csstype@npm:3.1.2"
checksum: e1a52e6c25c1314d6beef5168da704ab29c5186b877c07d822bd0806717d9a265e8493a2e35ca7e68d0f5d472d43fac1cdce70fd79fd0853dff81f3028d857b5
languageName: node
linkType: hard
"dayjs@npm:^1.10.7": "dayjs@npm:^1.10.7":
version: 1.11.7 version: 1.11.7
resolution: "dayjs@npm:1.11.7" resolution: "dayjs@npm:1.11.7"
@ -369,10 +373,10 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"eventemitter3@npm:^4.0.7": "eventemitter3@npm:^5.0.0":
version: 4.0.7 version: 5.0.0
resolution: "eventemitter3@npm:4.0.7" resolution: "eventemitter3@npm:5.0.0"
checksum: 1875311c42fcfe9c707b2712c32664a245629b42bb0a5a84439762dd0fd637fc54d078155ea83c2af9e0323c9ac13687e03cfba79b03af9f40c89b4960099374 checksum: b974bafbab860e0a5bbb21add4c4e82f9d5691c583c03f2e4c5d44a2d6c4556d79223621bdcfc6c8e14366a4af9df6b5ea9d6caf65fbffc80b66f3e1dceacbc9
languageName: node languageName: node
linkType: hard linkType: hard
@ -390,7 +394,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.14.4, follow-redirects@npm:^1.14.8": "follow-redirects@npm:^1.14.4, follow-redirects@npm:^1.14.8":
version: 1.15.2 version: 1.15.2
resolution: "follow-redirects@npm:1.15.2" resolution: "follow-redirects@npm:1.15.2"
peerDependenciesMeta: peerDependenciesMeta:
@ -457,6 +461,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"isomorphic-ws@npm:^5.0.0":
version: 5.0.0
resolution: "isomorphic-ws@npm:5.0.0"
peerDependencies:
ws: "*"
checksum: e20eb2aee09ba96247465fda40c6d22c1153394c0144fa34fe6609f341af4c8c564f60ea3ba762335a7a9c306809349f9b863c8beedf2beea09b299834ad5398
languageName: node
linkType: hard
"js-yaml@npm:^4.1.0": "js-yaml@npm:^4.1.0":
version: 4.1.0 version: 4.1.0
resolution: "js-yaml@npm:4.1.0" resolution: "js-yaml@npm:4.1.0"
@ -475,20 +488,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"lodash.flatten@npm:^4.4.0":
version: 4.4.0
resolution: "lodash.flatten@npm:4.4.0"
checksum: 0ac34a393d4b795d4b7421153d27c13ae67e08786c9cbb60ff5b732210d46f833598eee3fb3844bb10070e8488efe390ea53bb567377e0cb47e9e630bf0811cb
languageName: node
linkType: hard
"lodash.isequal@npm:^4.5.0":
version: 4.5.0
resolution: "lodash.isequal@npm:4.5.0"
checksum: da27515dc5230eb1140ba65ff8de3613649620e8656b19a6270afe4866b7bd461d9ba2ac8a48dcc57f7adac4ee80e1de9f965d89d4d81a0ad52bb3eec2609644
languageName: node
linkType: hard
"lodash@npm:^4.17.21": "lodash@npm:^4.17.21":
version: 4.17.21 version: 4.17.21
resolution: "lodash@npm:4.17.21" resolution: "lodash@npm:4.17.21"
@ -505,7 +504,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"long@npm:^5.2.0": "long@npm:^5.2.1":
version: 5.2.1 version: 5.2.1
resolution: "long@npm:5.2.1" resolution: "long@npm:5.2.1"
checksum: 9264da12d1b7df67e5aa6da4498144293caf1ad12e7f092efe4e9a2d32c53f0bbf7334f7cef997080a2a3af061142558ab366efa71698d98b1cdb883477445a7 checksum: 9264da12d1b7df67e5aa6da4498144293caf1ad12e7f092efe4e9a2d32c53f0bbf7334f7cef997080a2a3af061142558ab366efa71698d98b1cdb883477445a7
@ -544,13 +543,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"mobx@npm:^6.3.2":
version: 6.8.0
resolution: "mobx@npm:6.8.0"
checksum: f09bb079292ea59023a7e35a9c73ed577e3de9a0175ec3d5a2adc8192e2e3a352b29ec0981ee06d1d63f701f81bb7fc6cc19fd9089edf84a754a8a75ef00ef7f
languageName: node
linkType: hard
"mongodb@npm:^3.2.3": "mongodb@npm:^3.2.3":
version: 3.7.3 version: 3.7.3
resolution: "mongodb@npm:3.7.3" resolution: "mongodb@npm:3.7.3"
@ -750,14 +742,14 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"revolt-api@npm:0.5.16, revolt-api@npm:^0.5.16": "revolt-api@npm:^0.5.17, revolt-api@npm:latest":
version: 0.5.16 version: 0.5.17
resolution: "revolt-api@npm:0.5.16" resolution: "revolt-api@npm:0.5.17"
dependencies: dependencies:
"@insertish/oapi": 0.1.18 "@insertish/oapi": 0.1.18
axios: ^0.26.1 axios: ^0.26.1
lodash.defaultsdeep: ^4.6.1 lodash.defaultsdeep: ^4.6.1
checksum: ce39f61e371c1b7da0704191317bccf88b6630f1d8ffcef6bc9c699ebdc8cfbb3fcc5e054f96f9751c2f4a048398d4b349670cd067bcaad2e099d0c30efd9cfe checksum: aa722f4739c09bea46f738a1b9aef61af126e06aa924a61fcf33caa53561c5de4e7e2ddde26b496cdd0546e113cf324821fead0035973e2ebdb2633df482091b
languageName: node languageName: node
linkType: hard linkType: hard
@ -765,7 +757,6 @@ __metadata:
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "revolt-automod@workspace:." resolution: "revolt-automod@workspace:."
dependencies: dependencies:
"@janderedev/revolt.js": latest
"@types/monk": ^6.0.0 "@types/monk": ^6.0.0
automod: ^0.1.0 automod: ^0.1.0
axios: ^0.22.0 axios: ^0.22.0
@ -776,13 +767,30 @@ __metadata:
log75: ^2.2.0 log75: ^2.2.0
monk: ^7.3.4 monk: ^7.3.4
prom-client: ^14.0.1 prom-client: ^14.0.1
revolt-api: ^0.5.16 revolt-api: latest
revolt.js: ^7.0.0
typescript: ^4.4.3 typescript: ^4.4.3
ulid: ^2.3.0 ulid: ^2.3.0
xlsx: ^0.17.3 xlsx: ^0.17.3
languageName: unknown languageName: unknown
linkType: soft linkType: soft
"revolt.js@portal:../revolt.js::locator=revolt-automod%40workspace%3A.":
version: 0.0.0-use.local
resolution: "revolt.js@portal:../revolt.js::locator=revolt-automod%40workspace%3A."
dependencies:
"@solid-primitives/map": ^0.4.3
"@solid-primitives/set": ^0.4.3
eventemitter3: ^5.0.0
isomorphic-ws: ^5.0.0
long: ^5.2.1
revolt-api: ^0.5.17
solid-js: ^1.7.2
ulid: ^2.3.0
ws: ^8.13.0
languageName: node
linkType: soft
"safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2": "safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2":
version: 5.2.1 version: 5.2.1
resolution: "safe-buffer@npm:5.2.1" resolution: "safe-buffer@npm:5.2.1"
@ -806,6 +814,23 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"seroval@npm:^0.5.0":
version: 0.5.1
resolution: "seroval@npm:0.5.1"
checksum: a4c1e42d6a65ed12de3c1f1b6a5b6b996e575c5bc838e1998e92daed7bc05421f3f6c82096387082dba33c475d64a31d0d932ac9b693352549259216e38dc091
languageName: node
linkType: hard
"solid-js@npm:^1.7.2":
version: 1.7.3
resolution: "solid-js@npm:1.7.3"
dependencies:
csstype: ^3.1.0
seroval: ^0.5.0
checksum: 052a3148b6d0960312793781435005c16a7a80c2271e2bf2370ec22ec57ffd77e3e4a41335c1bd785ab36500adef86da79536445983efbed404db860e11593d4
languageName: node
linkType: hard
"sparse-bitfield@npm:^3.0.3": "sparse-bitfield@npm:^3.0.3":
version: 3.0.3 version: 3.0.3
resolution: "sparse-bitfield@npm:3.0.3" resolution: "sparse-bitfield@npm:3.0.3"
@ -956,7 +981,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"ws@npm:^8.2.2, ws@npm:^8.9.0": "ws@npm:^8.13.0, ws@npm:^8.9.0":
version: 8.13.0 version: 8.13.0
resolution: "ws@npm:8.13.0" resolution: "ws@npm:8.13.0"
peerDependencies: peerDependencies:

View file

@ -14,7 +14,6 @@
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@discordjs/rest": "^0.4.1", "@discordjs/rest": "^0.4.1",
"@janderedev/revolt.js": "latest",
"automod": "^0.1.0", "automod": "^0.1.0",
"axios": "^0.26.1", "axios": "^0.26.1",
"discord-api-types": "^0.31.2", "discord-api-types": "^0.31.2",
@ -25,7 +24,8 @@
"log75": "^2.2.0", "log75": "^2.2.0",
"monk": "^7.3.4", "monk": "^7.3.4",
"prom-client": "^14.0.1", "prom-client": "^14.0.1",
"revolt-api": "^0.5.3-rc.8", "revolt-api": "latest",
"revolt.js": "^7.0.0",
"smart-replace": "^1.0.2", "smart-replace": "^1.0.2",
"ulid": "^2.3.0" "ulid": "^2.3.0"
}, },
@ -34,6 +34,7 @@
"typescript": "^4.7.4" "typescript": "^4.7.4"
}, },
"resolutions": { "resolutions": {
"automod": "portal:../lib" "automod": "portal:../lib",
"revolt.js": "portal:../revolt.js"
} }
} }

View file

@ -303,7 +303,7 @@ client.on("interactionCreate", async (interaction) => {
embed.addField( embed.addField(
"Adding AutoMod to your server", "Adding AutoMod to your server",
`You can add the Revolt bot to your server ` + `You can add the Revolt bot to your server ` +
`[here](https://app.revolt.chat/bot/${revoltClient.user?._id} "Open Revolt"). To add the Discord counterpart, ` + `[here](https://app.revolt.chat/bot/${revoltClient.user?.id} "Open Revolt"). To add the Discord counterpart, ` +
`click [here](${INVITE_URL} "Add Discord bot").` `click [here](${INVITE_URL} "Add Discord bot").`
); );
@ -480,11 +480,11 @@ client.on("interactionCreate", async (interaction) => {
if (revoltMsg) { if (revoltMsg) {
const author = await revoltFetchUser( const author = await revoltFetchUser(
revoltMsg.author_id revoltMsg.authorId
); );
embed.addField( embed.addField(
"Message Author", "Message Author",
`**@${author?.username}** (${revoltMsg.author_id})` `**@${author?.username}** (${revoltMsg.authorId})`
); );
} }
} }

View file

@ -1,6 +1,6 @@
import { BRIDGED_MESSAGES, BRIDGE_CONFIG, BRIDGE_USER_CONFIG, logger } from ".."; import { BRIDGED_MESSAGES, BRIDGE_CONFIG, BRIDGE_USER_CONFIG, logger } from "..";
import { client } from "./client"; import { client } from "./client";
import { AUTUMN_URL, client as revoltClient } from "../revolt/client"; import { client as revoltClient } from "../revolt/client";
import axios from 'axios'; import axios from 'axios';
import { ulid } from "ulid"; import { ulid } from "ulid";
import GenericEmbed from "../types/GenericEmbed"; import GenericEmbed from "../types/GenericEmbed";
@ -196,7 +196,7 @@ client.on("messageCreate", async (message) => {
await BRIDGED_MESSAGES.update( await BRIDGED_MESSAGES.update(
{ "discord.messageId": message.id }, { "discord.messageId": message.id },
{ {
$set: { "revolt.messageId": msg._id }, $set: { "revolt.messageId": msg.id },
} }
); );
@ -233,7 +233,7 @@ client.on("messageCreate", async (message) => {
}); });
const res = await axios.post( const res = await axios.post(
`${AUTUMN_URL}/attachments`, `${revoltClient.configuration?.features.autumn.url}/attachments`,
formData, formData,
{ headers: formData.getHeaders() } { headers: formData.getHeaders() }
); );
@ -280,7 +280,7 @@ client.on("messageCreate", async (message) => {
}); });
const res = await axios.post( const res = await axios.post(
`${AUTUMN_URL}/attachments`, `${revoltClient.configuration?.features.autumn.url}/attachments`,
formData, formData,
{ headers: formData.getHeaders() } { headers: formData.getHeaders() }
); );
@ -338,7 +338,7 @@ client.on("messageCreate", async (message) => {
await axios await axios
.post( .post(
`${revoltClient.apiURL}/channels/${channel._id}/messages`, `${revoltClient.options.baseURL}/channels/${channel.id}/messages`,
payload, payload,
{ {
headers: { headers: {
@ -474,7 +474,7 @@ async function renderMessageBody(message: string): Promise<string> {
: undefined; : undefined;
return revoltChannel return revoltChannel
? `<#${revoltChannel._id}>` ? `<#${revoltChannel.id}>`
: `#${(channel as TextChannel)?.name || id}`; : `#${(channel as TextChannel)?.name || id}`;
}, },
{ cacheMatchResults: true, maxMatches: 10 } { cacheMatchResults: true, maxMatches: 10 }

View file

@ -1,21 +1,18 @@
import { Client } from '@janderedev/revolt.js'; import { Client } from 'revolt.js';
import axios from 'axios';
import { logger } from '..'; import { logger } from '..';
let AUTUMN_URL = `http://autumnUrl`; let AUTUMN_URL: string = '';
const client = new Client({ const client = new Client({
apiURL: process.env.REVOLT_API_URL, baseURL: process.env.REVOLT_API_URL || 'https://api.revolt.chat',
autoReconnect: true, autoReconnect: true,
}); });
const login = () => new Promise((resolve: (value: Client) => void) => { const login = () => new Promise((resolve: (value: Client) => void) => {
client.loginBot(process.env['REVOLT_TOKEN']!); client.loginBot(process.env['REVOLT_TOKEN']!);
client.once('ready', async () => { client.once('ready', async () => {
logger.info(`Revolt: ${client.user?.username} ready - ${client.servers.size} servers`); logger.info(`Revolt: ${client.user?.username} ready - ${client.servers.size()} servers`);
AUTUMN_URL = client.configuration?.features.autumn.url ?? '';
const apiConfig = await axios.get(client.apiURL);
AUTUMN_URL = apiConfig.data?.features?.autumn?.url;
resolve(client); resolve(client);
}); });

View file

@ -26,7 +26,7 @@ fetchEmojiList()
) )
.catch((e) => console.error(e)); .catch((e) => console.error(e));
client.on("message/delete", async (id) => { client.on("messageDelete", async (id) => {
try { try {
logger.debug(`[D] Revolt: ${id}`); logger.debug(`[D] Revolt: ${id}`);
@ -83,15 +83,15 @@ client.on("message/delete", async (id) => {
} }
}); });
client.on("message/update", async (message) => { client.on("messageUpdate", async (message) => {
if (!message.content || typeof message.content != "string") return; if (!message.content || typeof message.content != "string") return;
if (message.author_id == client.user?._id) return; if (message.authorId == client.user?.id) return;
try { try {
logger.debug(`[E] Revolt: ${message.content}`); logger.debug(`[E] Revolt: ${message.content}`);
const [bridgeCfg, bridgedMsg] = await Promise.all([ const [bridgeCfg, bridgedMsg] = await Promise.all([
BRIDGE_CONFIG.findOne({ revolt: message.channel_id }), BRIDGE_CONFIG.findOne({ revolt: message.channelId }),
BRIDGED_MESSAGES.findOne({ "revolt.nonce": message.nonce }), BRIDGED_MESSAGES.findOne({ "revolt.nonce": message.nonce }),
]); ]);
@ -127,18 +127,18 @@ client.on("message/update", async (message) => {
} }
}); });
client.on("message", async (message) => { client.on("messageCreate", async (message) => {
try { try {
logger.debug(`[M] Revolt: ${message._id} ${message.content}`); logger.debug(`[M] Revolt: ${message.id} ${message.content}`);
const [bridgeCfg, bridgedMsg, ...repliedMessages] = await Promise.all([ const [bridgeCfg, bridgedMsg, ...repliedMessages] = await Promise.all([
BRIDGE_CONFIG.findOne({ revolt: message.channel_id }), BRIDGE_CONFIG.findOne({ revolt: message.channelId }),
BRIDGED_MESSAGES.findOne( BRIDGED_MESSAGES.findOne(
message.nonce message.nonce
? { "revolt.nonce": message.nonce } ? { "revolt.nonce": message.nonce }
: { "revolt.messageId": message._id } : { "revolt.messageId": message.id }
), ),
...(message.reply_ids?.map((id) => ...(message.replyIds?.map((id) =>
BRIDGED_MESSAGES.findOne({ "revolt.messageId": id }) BRIDGED_MESSAGES.findOne({ "revolt.messageId": id })
) ?? []), ) ?? []),
]); ]);
@ -147,7 +147,7 @@ client.on("message", async (message) => {
return logger.debug( return logger.debug(
`Revolt: Message has already been bridged; ignoring` `Revolt: Message has already been bridged; ignoring`
); );
if (message.system && bridgeCfg?.config?.disable_system_messages) if (message.systemMessage && bridgeCfg?.config?.disable_system_messages)
return logger.debug( return logger.debug(
`Revolt: System message bridging disabled; ignoring` `Revolt: System message bridging disabled; ignoring`
); );
@ -182,7 +182,7 @@ client.on("message", async (message) => {
token: hook.token || "", token: hook.token || "",
}; };
await BRIDGE_CONFIG.update( await BRIDGE_CONFIG.update(
{ revolt: message.channel_id }, { revolt: message.channelId },
{ {
$set: { $set: {
discordWebhook: bridgeCfg.discordWebhook, discordWebhook: bridgeCfg.discordWebhook,
@ -193,7 +193,7 @@ client.on("message", async (message) => {
logger.warn( logger.warn(
`Unable to create new webhook for channel ${bridgeCfg.discord}; Deleting link\n${e}` `Unable to create new webhook for channel ${bridgeCfg.discord}; Deleting link\n${e}`
); );
await BRIDGE_CONFIG.remove({ revolt: message.channel_id }); await BRIDGE_CONFIG.remove({ revolt: message.channelId });
await message.channel await message.channel
?.sendMessage( ?.sendMessage(
":warning: I was unable to create a webhook in the bridged Discord channel. " + ":warning: I was unable to create a webhook in the bridged Discord channel. " +
@ -206,15 +206,15 @@ client.on("message", async (message) => {
} }
await BRIDGED_MESSAGES.update( await BRIDGED_MESSAGES.update(
{ "revolt.messageId": message._id }, { "revolt.messageId": message.id },
{ {
$set: { $set: {
revolt: { revolt: {
messageId: message._id, messageId: message.id,
nonce: message.nonce, nonce: message.nonce,
}, },
channels: { channels: {
revolt: message.channel_id, revolt: message.channelId,
discord: bridgeCfg.discord, discord: bridgeCfg.discord,
}, },
}, },
@ -238,23 +238,23 @@ client.on("message", async (message) => {
content: content:
message.content message.content
? await renderMessageBody(message.content) ? await renderMessageBody(message.content)
: message.system : message.systemMessage
? await renderSystemMessage(message.system) ? await renderSystemMessage(message.systemMessage)
: undefined, : undefined,
username: message.system username: message.systemMessage
? "Revolt" ? "Revolt"
: (bridgeCfg.config?.bridge_nicknames : (bridgeCfg.config?.bridge_nicknames
? message.masquerade?.name ?? ? message.masquerade?.name ??
message.member?.nickname ?? message.member?.nickname ??
message.author?.username message.author?.username
: message.author?.username) ?? "Unknown user", : message.author?.username) ?? "Unknown user",
avatarURL: message.system avatarURL: message.systemMessage
? "https://app.revolt.chat/assets/logo_round.png" ? "https://app.revolt.chat/assets/logo_round.png"
: bridgeCfg.config?.bridge_nicknames : bridgeCfg.config?.bridge_nicknames
? message.masquerade?.avatar ?? ? message.masquerade?.avatar ??
message.member?.generateAvatarURL({ max_side: 128 }) ?? message.member?.avatarURL ??
message.author?.generateAvatarURL({ max_side: 128 }) message.author?.avatarURL
: message.author?.generateAvatarURL({ max_side: 128 }), : message.author?.avatarURL,
embeds: message.embeds?.length embeds: message.embeds?.length
? message.embeds ? message.embeds
.filter((e) => e.type == "Text") .filter((e) => e.type == "Text")
@ -293,15 +293,15 @@ client.on("message", async (message) => {
); );
} else { } else {
const msg = await revoltFetchMessage( const msg = await revoltFetchMessage(
message.reply_ids?.[0], message.replyIds?.[0],
message.channel message.channel
); );
const brMsg = repliedMessages.find( const brMsg = repliedMessages.find(
(m) => m?.revolt.messageId == msg?._id (m) => m?.revolt.messageId == msg?.id
); );
embed.setAuthor({ embed.setAuthor({
name: `@${msg?.author?.username ?? "Unknown"}`, name: `@${msg?.author?.username ?? "Unknown"}`,
iconURL: msg?.author?.generateAvatarURL({ size: 64 }), iconURL: msg?.author?.avatarURL,
url: brMsg url: brMsg
? `https://discord.com/channels/${ ? `https://discord.com/channels/${
channel.guildId channel.guildId
@ -338,7 +338,7 @@ client.on("message", async (message) => {
msgUrl = msg.url; msgUrl = msg.url;
} else { } else {
const brMsg = repliedMessages.find( const brMsg = repliedMessages.find(
(m) => m?.revolt.messageId == msg?._id (m) => m?.revolt.messageId == msg?.id
); );
if (brMsg) if (brMsg)
msgUrl = `https://discord.com/channels/${ msgUrl = `https://discord.com/channels/${
@ -367,7 +367,7 @@ client.on("message", async (message) => {
for (const attachment of message.attachments) { for (const attachment of message.attachments) {
payload.files.push({ payload.files.push({
attachment: `${AUTUMN_URL}/attachments/${attachment._id}/${attachment.filename}`, attachment: `${AUTUMN_URL}/attachments/${attachment.id}/${attachment.filename}`,
name: attachment.filename, name: attachment.filename,
}); });
} }
@ -378,7 +378,7 @@ client.on("message", async (message) => {
.then(async (res) => { .then(async (res) => {
await BRIDGED_MESSAGES.update( await BRIDGED_MESSAGES.update(
{ {
"revolt.messageId": message._id, "revolt.messageId": message.id,
}, },
{ {
$set: { $set: {
@ -400,7 +400,7 @@ client.on("message", async (message) => {
"Revolt: Got Unknown Webhook error, deleting webhook config" "Revolt: Got Unknown Webhook error, deleting webhook config"
); );
await BRIDGE_CONFIG.update( await BRIDGE_CONFIG.update(
{ revolt: message.channel_id }, { revolt: message.channelId },
{ $set: { discordWebhook: undefined } } { $set: { discordWebhook: undefined } }
); );
} catch (e) { } catch (e) {
@ -436,7 +436,7 @@ async function renderMessageBody(message: string): Promise<string> {
const channel = client.channels.get(id); const channel = client.channels.get(id);
const bridgeCfg = channel const bridgeCfg = channel
? await BRIDGE_CONFIG.findOne({ revolt: channel._id }) ? await BRIDGE_CONFIG.findOne({ revolt: channel.id })
: undefined; : undefined;
const discordChannel = bridgeCfg?.discord const discordChannel = bridgeCfg?.discord
? discordClient.channels.cache.get(bridgeCfg.discord) ? discordClient.channels.cache.get(bridgeCfg.discord)

View file

@ -1,6 +1,6 @@
import { Channel } from "@janderedev/revolt.js/dist/maps/Channels"; import { Channel } from "revolt.js";
import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { Message } from "revolt.js";
import { User } from "@janderedev/revolt.js/dist/maps/Users"; import { User } from "revolt.js";
import { Message as DiscordMessage, TextChannel, User as DiscordUser } from "discord.js"; import { Message as DiscordMessage, TextChannel, User as DiscordUser } from "discord.js";
import { client as discordClient } from "./discord/client"; import { client as discordClient } from "./discord/client";
import { client as revoltClient } from "./revolt/client" import { client as revoltClient } from "./revolt/client"

View file

@ -41,22 +41,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@insertish/exponential-backoff@npm:3.1.0-patch.2":
version: 3.1.0-patch.2
resolution: "@insertish/exponential-backoff@npm:3.1.0-patch.2"
checksum: 510a531965965c8cc633a91653ca09ffa8408925eb403d07c072bed065ec8ce429b4fd42fb0639a3dbee73d300d4422c306ebaaab3292b06778a224a2b5b0bf1
languageName: node
linkType: hard
"@insertish/isomorphic-ws@npm:^4.0.1":
version: 4.0.1
resolution: "@insertish/isomorphic-ws@npm:4.0.1"
peerDependencies:
ws: "*"
checksum: 64e6464b379784d0c8df31868eb8301b3e3827f91131755c38f66a007fcd791314c6ef49f3ead37bb5d62cc7fd52f2171b2e0ce04564a744905f72d3cd86f1ba
languageName: node
linkType: hard
"@insertish/oapi@npm:0.1.18": "@insertish/oapi@npm:0.1.18":
version: 0.1.18 version: 0.1.18
resolution: "@insertish/oapi@npm:0.1.18" resolution: "@insertish/oapi@npm:0.1.18"
@ -75,26 +59,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@janderedev/revolt.js@npm:latest":
version: 6.0.20-patch.9
resolution: "@janderedev/revolt.js@npm:6.0.20-patch.9"
dependencies:
"@insertish/exponential-backoff": 3.1.0-patch.2
"@insertish/isomorphic-ws": ^4.0.1
axios: ^0.21.4
eventemitter3: ^4.0.7
lodash.defaultsdeep: ^4.6.1
lodash.flatten: ^4.4.0
lodash.isequal: ^4.5.0
long: ^5.2.0
mobx: ^6.3.2
revolt-api: 0.5.16
ulid: ^2.3.0
ws: ^8.2.2
checksum: 942f8cb7339f6378738d97ff788680dc63c287624e749b95b867a82c877bc6416a4a7b85264bf8797e034132d5a84843d75b820b6a1c37a760a88f13114772a0
languageName: node
linkType: hard
"@sapphire/async-queue@npm:^1.3.1, @sapphire/async-queue@npm:^1.5.0": "@sapphire/async-queue@npm:^1.3.1, @sapphire/async-queue@npm:^1.5.0":
version: 1.5.0 version: 1.5.0
resolution: "@sapphire/async-queue@npm:1.5.0" resolution: "@sapphire/async-queue@npm:1.5.0"
@ -119,6 +83,48 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@solid-primitives/map@npm:^0.4.3":
version: 0.4.3
resolution: "@solid-primitives/map@npm:0.4.3"
dependencies:
"@solid-primitives/trigger": ^1.0.3
peerDependencies:
solid-js: ^1.6.12
checksum: e2408d7309c2bc0b93126771ad796cc3cbc2b150a03b4f3d4963dbc6df2ad26e671277fc14aafe1c117f1228c35557686e709accd6237ac511d2e05a6682006d
languageName: node
linkType: hard
"@solid-primitives/set@npm:^0.4.3":
version: 0.4.3
resolution: "@solid-primitives/set@npm:0.4.3"
dependencies:
"@solid-primitives/trigger": ^1.0.3
peerDependencies:
solid-js: ^1.6.12
checksum: fcab5679185633b887d6d9ef4c12ded12d1773969a66079ce98dc18bbb2869f9fe743a1f3cd1f5721b52dcd274ae096470daa8ab1284643b4b26eeb28b7a5698
languageName: node
linkType: hard
"@solid-primitives/trigger@npm:^1.0.3":
version: 1.0.5
resolution: "@solid-primitives/trigger@npm:1.0.5"
dependencies:
"@solid-primitives/utils": ^6.0.0
peerDependencies:
solid-js: ^1.6.12
checksum: 5f137ec425b317c09de6b994928992201206c16be7a01f7add46e0ee987d76a947a7f4f9396a945eeb671c43307b6f5d55bd57d90738880cebdaa0907aca65dd
languageName: node
linkType: hard
"@solid-primitives/utils@npm:^6.0.0":
version: 6.0.0
resolution: "@solid-primitives/utils@npm:6.0.0"
peerDependencies:
solid-js: ^1.6.12
checksum: c581b995e2d16c9ed0546baef52a9e60f54dda457a3733bac467a19f2a63227179eb0ec6faa16397af4cacc13fa281288cf967a206b0a75255412fafadc55411
languageName: node
linkType: hard
"@types/bson@npm:*": "@types/bson@npm:*":
version: 4.0.5 version: 4.0.5
resolution: "@types/bson@npm:4.0.5" resolution: "@types/bson@npm:4.0.5"
@ -191,15 +197,6 @@ __metadata:
languageName: node languageName: node
linkType: soft linkType: soft
"axios@npm:^0.21.4":
version: 0.21.4
resolution: "axios@npm:0.21.4"
dependencies:
follow-redirects: ^1.14.0
checksum: 44245f24ac971e7458f3120c92f9d66d1fc695e8b97019139de5b0cc65d9b8104647db01e5f46917728edfc0cfd88eb30fc4c55e6053eef4ace76768ce95ff3c
languageName: node
linkType: hard
"axios@npm:^0.26.1": "axios@npm:^0.26.1":
version: 0.26.1 version: 0.26.1
resolution: "axios@npm:0.26.1" resolution: "axios@npm:0.26.1"
@ -231,7 +228,6 @@ __metadata:
resolution: "bridge@workspace:." resolution: "bridge@workspace:."
dependencies: dependencies:
"@discordjs/rest": ^0.4.1 "@discordjs/rest": ^0.4.1
"@janderedev/revolt.js": latest
automod: ^0.1.0 automod: ^0.1.0
axios: ^0.26.1 axios: ^0.26.1
discord-api-types: ^0.31.2 discord-api-types: ^0.31.2
@ -242,7 +238,8 @@ __metadata:
log75: ^2.2.0 log75: ^2.2.0
monk: ^7.3.4 monk: ^7.3.4
prom-client: ^14.0.1 prom-client: ^14.0.1
revolt-api: ^0.5.3-rc.8 revolt-api: latest
revolt.js: ^7.0.0
smart-replace: ^1.0.2 smart-replace: ^1.0.2
typescript: ^4.7.4 typescript: ^4.7.4
ulid: ^2.3.0 ulid: ^2.3.0
@ -281,6 +278,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"csstype@npm:^3.1.0":
version: 3.1.2
resolution: "csstype@npm:3.1.2"
checksum: e1a52e6c25c1314d6beef5168da704ab29c5186b877c07d822bd0806717d9a265e8493a2e35ca7e68d0f5d472d43fac1cdce70fd79fd0853dff81f3028d857b5
languageName: node
linkType: hard
"debug@npm:*": "debug@npm:*":
version: 4.3.4 version: 4.3.4
resolution: "debug@npm:4.3.4" resolution: "debug@npm:4.3.4"
@ -359,10 +363,10 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"eventemitter3@npm:^4.0.7": "eventemitter3@npm:^5.0.0":
version: 4.0.7 version: 5.0.0
resolution: "eventemitter3@npm:4.0.7" resolution: "eventemitter3@npm:5.0.0"
checksum: 1875311c42fcfe9c707b2712c32664a245629b42bb0a5a84439762dd0fd637fc54d078155ea83c2af9e0323c9ac13687e03cfba79b03af9f40c89b4960099374 checksum: b974bafbab860e0a5bbb21add4c4e82f9d5691c583c03f2e4c5d44a2d6c4556d79223621bdcfc6c8e14366a4af9df6b5ea9d6caf65fbffc80b66f3e1dceacbc9
languageName: node languageName: node
linkType: hard linkType: hard
@ -373,7 +377,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.14.8": "follow-redirects@npm:^1.14.8":
version: 1.15.2 version: 1.15.2
resolution: "follow-redirects@npm:1.15.2" resolution: "follow-redirects@npm:1.15.2"
peerDependenciesMeta: peerDependenciesMeta:
@ -433,6 +437,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"isomorphic-ws@npm:^5.0.0":
version: 5.0.0
resolution: "isomorphic-ws@npm:5.0.0"
peerDependencies:
ws: "*"
checksum: e20eb2aee09ba96247465fda40c6d22c1153394c0144fa34fe6609f341af4c8c564f60ea3ba762335a7a9c306809349f9b863c8beedf2beea09b299834ad5398
languageName: node
linkType: hard
"js-yaml@npm:^4.1.0": "js-yaml@npm:^4.1.0":
version: 4.1.0 version: 4.1.0
resolution: "js-yaml@npm:4.1.0" resolution: "js-yaml@npm:4.1.0"
@ -460,20 +473,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"lodash.flatten@npm:^4.4.0":
version: 4.4.0
resolution: "lodash.flatten@npm:4.4.0"
checksum: 0ac34a393d4b795d4b7421153d27c13ae67e08786c9cbb60ff5b732210d46f833598eee3fb3844bb10070e8488efe390ea53bb567377e0cb47e9e630bf0811cb
languageName: node
linkType: hard
"lodash.isequal@npm:^4.5.0":
version: 4.5.0
resolution: "lodash.isequal@npm:4.5.0"
checksum: da27515dc5230eb1140ba65ff8de3613649620e8656b19a6270afe4866b7bd461d9ba2ac8a48dcc57f7adac4ee80e1de9f965d89d4d81a0ad52bb3eec2609644
languageName: node
linkType: hard
"lodash@npm:^4.17.21": "lodash@npm:^4.17.21":
version: 4.17.21 version: 4.17.21
resolution: "lodash@npm:4.17.21" resolution: "lodash@npm:4.17.21"
@ -490,7 +489,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"long@npm:^5.2.0": "long@npm:^5.2.1":
version: 5.2.1 version: 5.2.1
resolution: "long@npm:5.2.1" resolution: "long@npm:5.2.1"
checksum: 9264da12d1b7df67e5aa6da4498144293caf1ad12e7f092efe4e9a2d32c53f0bbf7334f7cef997080a2a3af061142558ab366efa71698d98b1cdb883477445a7 checksum: 9264da12d1b7df67e5aa6da4498144293caf1ad12e7f092efe4e9a2d32c53f0bbf7334f7cef997080a2a3af061142558ab366efa71698d98b1cdb883477445a7
@ -529,13 +528,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"mobx@npm:^6.3.2":
version: 6.8.0
resolution: "mobx@npm:6.8.0"
checksum: f09bb079292ea59023a7e35a9c73ed577e3de9a0175ec3d5a2adc8192e2e3a352b29ec0981ee06d1d63f701f81bb7fc6cc19fd9089edf84a754a8a75ef00ef7f
languageName: node
linkType: hard
"mongodb@npm:^3.2.3": "mongodb@npm:^3.2.3":
version: 3.7.3 version: 3.7.3
resolution: "mongodb@npm:3.7.3" resolution: "mongodb@npm:3.7.3"
@ -726,17 +718,33 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"revolt-api@npm:0.5.16, revolt-api@npm:^0.5.3-rc.8": "revolt-api@npm:^0.5.17, revolt-api@npm:latest":
version: 0.5.16 version: 0.5.17
resolution: "revolt-api@npm:0.5.16" resolution: "revolt-api@npm:0.5.17"
dependencies: dependencies:
"@insertish/oapi": 0.1.18 "@insertish/oapi": 0.1.18
axios: ^0.26.1 axios: ^0.26.1
lodash.defaultsdeep: ^4.6.1 lodash.defaultsdeep: ^4.6.1
checksum: ce39f61e371c1b7da0704191317bccf88b6630f1d8ffcef6bc9c699ebdc8cfbb3fcc5e054f96f9751c2f4a048398d4b349670cd067bcaad2e099d0c30efd9cfe checksum: aa722f4739c09bea46f738a1b9aef61af126e06aa924a61fcf33caa53561c5de4e7e2ddde26b496cdd0546e113cf324821fead0035973e2ebdb2633df482091b
languageName: node languageName: node
linkType: hard linkType: hard
"revolt.js@portal:../revolt.js::locator=bridge%40workspace%3A.":
version: 0.0.0-use.local
resolution: "revolt.js@portal:../revolt.js::locator=bridge%40workspace%3A."
dependencies:
"@solid-primitives/map": ^0.4.3
"@solid-primitives/set": ^0.4.3
eventemitter3: ^5.0.0
isomorphic-ws: ^5.0.0
long: ^5.2.1
revolt-api: ^0.5.17
solid-js: ^1.7.2
ulid: ^2.3.0
ws: ^8.13.0
languageName: node
linkType: soft
"safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2": "safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2":
version: 5.2.1 version: 5.2.1
resolution: "safe-buffer@npm:5.2.1" resolution: "safe-buffer@npm:5.2.1"
@ -760,6 +768,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"seroval@npm:^0.5.0":
version: 0.5.1
resolution: "seroval@npm:0.5.1"
checksum: a4c1e42d6a65ed12de3c1f1b6a5b6b996e575c5bc838e1998e92daed7bc05421f3f6c82096387082dba33c475d64a31d0d932ac9b693352549259216e38dc091
languageName: node
linkType: hard
"smart-replace@npm:^1.0.2": "smart-replace@npm:^1.0.2":
version: 1.0.2 version: 1.0.2
resolution: "smart-replace@npm:1.0.2" resolution: "smart-replace@npm:1.0.2"
@ -767,6 +782,16 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"solid-js@npm:^1.7.2":
version: 1.7.3
resolution: "solid-js@npm:1.7.3"
dependencies:
csstype: ^3.1.0
seroval: ^0.5.0
checksum: 052a3148b6d0960312793781435005c16a7a80c2271e2bf2370ec22ec57ffd77e3e4a41335c1bd785ab36500adef86da79536445983efbed404db860e11593d4
languageName: node
linkType: hard
"sparse-bitfield@npm:^3.0.3": "sparse-bitfield@npm:^3.0.3":
version: 3.0.3 version: 3.0.3
resolution: "sparse-bitfield@npm:3.0.3" resolution: "sparse-bitfield@npm:3.0.3"
@ -894,7 +919,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"ws@npm:^8.2.2, ws@npm:^8.9.0": "ws@npm:^8.13.0, ws@npm:^8.9.0":
version: 8.13.0 version: 8.13.0
resolution: "ws@npm:8.13.0" resolution: "ws@npm:8.13.0"
peerDependencies: peerDependencies:

1
revolt.js Submodule

@ -0,0 +1 @@
Subproject commit d452295c85c0d700ea536ebed2061c5daf960612