add option to bridge nicknames/masquerade data
This commit is contained in:
parent
0408c4b0a5
commit
55f5e339e1
5 changed files with 392 additions and 179 deletions
|
@ -7,18 +7,20 @@ import { BRIDGED_MESSAGES, BRIDGE_CONFIG, BRIDGE_REQUESTS, BRIDGE_USER_CONFIG, l
|
||||||
import { MessageEmbed, TextChannel } from "discord.js";
|
import { MessageEmbed, TextChannel } from "discord.js";
|
||||||
import { revoltFetchMessage, revoltFetchUser } from "../util";
|
import { revoltFetchMessage, revoltFetchUser } from "../util";
|
||||||
import { client as revoltClient } from "../revolt/client";
|
import { client as revoltClient } from "../revolt/client";
|
||||||
|
import { CONFIG_KEYS } from "../types/ConfigKeys";
|
||||||
|
|
||||||
const PRIVACY_POLICY_URL = 'https://github.com/janderedev/automod/wiki/Privacy-Policy';
|
const PRIVACY_POLICY_URL =
|
||||||
|
"https://github.com/janderedev/automod/wiki/Privacy-Policy";
|
||||||
|
|
||||||
const COMMANDS: any[] = [
|
const COMMANDS: any[] = [
|
||||||
{
|
{
|
||||||
name: 'bridge',
|
name: "bridge",
|
||||||
description: 'Confirm or delete Revolt bridges',
|
description: "Confirm or delete Revolt bridges",
|
||||||
type: 1, // Slash command
|
type: 1, // Slash command
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
name: 'confirm',
|
name: "confirm",
|
||||||
description: 'Confirm a bridge initiated from Revolt',
|
description: "Confirm a bridge initiated from Revolt",
|
||||||
type: 1, // Subcommand
|
type: 1, // Subcommand
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
|
@ -26,99 +28,153 @@ const COMMANDS: any[] = [
|
||||||
description: "The bridge request ID",
|
description: "The bridge request ID",
|
||||||
required: true,
|
required: true,
|
||||||
type: 3,
|
type: 3,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'unlink',
|
name: "unlink",
|
||||||
description: 'Unbridge the current channel',
|
description: "Unbridge the current channel",
|
||||||
type: 1,
|
type: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'help',
|
name: "help",
|
||||||
description: 'Usage instructions',
|
description: "Usage instructions",
|
||||||
type: 1,
|
type: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'opt_out',
|
name: "opt_out",
|
||||||
description: 'Opt out of having your messages bridged',
|
description: "Opt out of having your messages bridged",
|
||||||
type: 1,
|
type: 1,
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
name: 'opt_out',
|
name: "opt_out",
|
||||||
description: 'Whether you wish to opt out of having your messages bridged',
|
description:
|
||||||
|
"Whether you wish to opt out of having your messages bridged",
|
||||||
optional: true,
|
optional: true,
|
||||||
type: 5 // Boolean
|
type: 5, // Boolean
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'status',
|
name: "status",
|
||||||
description: 'Find out whether this channel is bridged to Revolt',
|
description:
|
||||||
type: 1
|
"Find out whether this channel is bridged to Revolt",
|
||||||
}
|
type: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "config",
|
||||||
|
description: "Bridge configuration options for this channel",
|
||||||
|
type: 1,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: "key",
|
||||||
|
description: "The configuration option to change",
|
||||||
|
type: 3, // String
|
||||||
|
required: true,
|
||||||
|
choices: Object.entries(CONFIG_KEYS).map((conf) => ({
|
||||||
|
name: conf[1].friendlyName,
|
||||||
|
value: conf[0],
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "value",
|
||||||
|
description:
|
||||||
|
"The new value for the option. Leave empty to get current state",
|
||||||
|
type: 5, // Boolean
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Message Info',
|
name: "Message Info",
|
||||||
description: '',
|
description: "",
|
||||||
type: 3, // Message context menu
|
type: 3, // Message context menu
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const rest = new REST({ version: '9' }).setToken(process.env['DISCORD_TOKEN']!);
|
const rest = new REST({ version: "9" }).setToken(process.env["DISCORD_TOKEN"]!);
|
||||||
|
|
||||||
client.once('ready', async () => {
|
client.once("ready", async () => {
|
||||||
try {
|
try {
|
||||||
logger.info(`Refreshing application commands.`);
|
logger.info(`Refreshing application commands.`);
|
||||||
|
|
||||||
if (process.env.NODE_ENV != 'production' && process.env.DEV_GUILD) {
|
if (process.env.NODE_ENV != "production" && process.env.DEV_GUILD) {
|
||||||
await rest.put(
|
await rest.put(
|
||||||
Routes.applicationGuildCommands(client.user!.id, process.env.DEV_GUILD),
|
Routes.applicationGuildCommands(
|
||||||
{ body: COMMANDS },
|
client.user!.id,
|
||||||
|
process.env.DEV_GUILD
|
||||||
|
),
|
||||||
|
{ body: COMMANDS }
|
||||||
|
);
|
||||||
|
logger.done(
|
||||||
|
`Application commands for ${process.env.DEV_GUILD} have been updated.`
|
||||||
);
|
);
|
||||||
logger.done(`Application commands for ${process.env.DEV_GUILD} have been updated.`);
|
|
||||||
} else {
|
} else {
|
||||||
await rest.put(
|
await rest.put(Routes.applicationCommands(client.user!.id), {
|
||||||
Routes.applicationCommands(client.user!.id),
|
body: COMMANDS,
|
||||||
{ body: COMMANDS },
|
});
|
||||||
);
|
|
||||||
logger.done(`Global application commands have been updated.`);
|
logger.done(`Global application commands have been updated.`);
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('interactionCreate', async interaction => {
|
client.on("interactionCreate", async (interaction) => {
|
||||||
try {
|
try {
|
||||||
if (interaction.isCommand()) {
|
if (interaction.isCommand()) {
|
||||||
logger.debug(`Command received: /${interaction.commandName}`);
|
logger.debug(`Command received: /${interaction.commandName}`);
|
||||||
|
|
||||||
// The revolutionary Jan command handler
|
// The revolutionary Jan command handler
|
||||||
switch(interaction.commandName) {
|
switch (interaction.commandName) {
|
||||||
case 'bridge':
|
case "bridge":
|
||||||
if (!interaction.memberPermissions?.has('MANAGE_GUILD') &&
|
if (
|
||||||
['confirm', 'unlink'].includes(interaction.options.getSubcommand(true))
|
!interaction.memberPermissions?.has("MANAGE_GUILD") &&
|
||||||
|
["confirm", "unlink"].includes(
|
||||||
|
interaction.options.getSubcommand(true)
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
return await interaction.reply({ content: `\`MANAGE_GUILD\` permission is required for this.`, ephemeral: true });
|
return await interaction.reply({
|
||||||
|
content: `\`MANAGE_GUILD\` permission is required for this.`,
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const ownPerms = (interaction.channel as TextChannel).permissionsFor(client.user!)!;
|
const ownPerms = (
|
||||||
switch(interaction.options.getSubcommand(true)) {
|
interaction.channel as TextChannel
|
||||||
case 'confirm':
|
).permissionsFor(client.user!)!;
|
||||||
if (!ownPerms.has('MANAGE_WEBHOOKS'))
|
switch (interaction.options.getSubcommand(true)) {
|
||||||
return interaction.reply('Sorry, I lack permission to manage webhooks in this channel.');
|
case "confirm": {
|
||||||
|
if (!ownPerms.has("MANAGE_WEBHOOKS"))
|
||||||
|
return interaction.reply(
|
||||||
|
"Sorry, I lack permission to manage webhooks in this channel."
|
||||||
|
);
|
||||||
|
|
||||||
const id = interaction.options.getString('id', true);
|
const id = interaction.options.getString(
|
||||||
const request = await BRIDGE_REQUESTS.findOne({ id: id });
|
"id",
|
||||||
if (!request || request.expires < Date.now()) return await interaction.reply('Unknown ID.');
|
true
|
||||||
|
);
|
||||||
|
const request = await BRIDGE_REQUESTS.findOne({
|
||||||
|
id: id,
|
||||||
|
});
|
||||||
|
if (!request || request.expires < Date.now())
|
||||||
|
return await interaction.reply("Unknown ID.");
|
||||||
|
|
||||||
const bridgedCount = await BRIDGE_CONFIG.count({ discord: interaction.channelId });
|
const bridgedCount = await BRIDGE_CONFIG.count({
|
||||||
if (bridgedCount > 0) return await interaction.reply('This channel is already bridged.');
|
discord: interaction.channelId,
|
||||||
|
});
|
||||||
|
if (bridgedCount > 0)
|
||||||
|
return await interaction.reply(
|
||||||
|
"This channel is already bridged."
|
||||||
|
);
|
||||||
|
|
||||||
const webhook = await (interaction.channel as TextChannel)
|
const webhook = await(
|
||||||
.createWebhook('AutoMod Bridge', { avatar: client.user?.avatarURL() });
|
interaction.channel as TextChannel
|
||||||
|
).createWebhook("AutoMod Bridge", {
|
||||||
|
avatar: client.user?.avatarURL(),
|
||||||
|
});
|
||||||
|
|
||||||
await BRIDGE_REQUESTS.remove({ id: id });
|
await BRIDGE_REQUESTS.remove({ id: id });
|
||||||
await BRIDGE_CONFIG.insert({
|
await BRIDGE_CONFIG.insert({
|
||||||
|
@ -126,58 +182,133 @@ client.on('interactionCreate', async interaction => {
|
||||||
revolt: request.revolt,
|
revolt: request.revolt,
|
||||||
discordWebhook: {
|
discordWebhook: {
|
||||||
id: webhook.id,
|
id: webhook.id,
|
||||||
token: webhook.token || '',
|
token: webhook.token || "",
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return await interaction.reply(`✅ Channel bridged!`);
|
return await interaction.reply(
|
||||||
case 'unlink':
|
`✅ Channel bridged!`
|
||||||
const res = await BRIDGE_CONFIG.findOneAndDelete({ discord: interaction.channelId });
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
case "unlink": {
|
||||||
|
const res = await BRIDGE_CONFIG.findOneAndDelete({
|
||||||
|
discord: interaction.channelId,
|
||||||
|
});
|
||||||
if (res?._id) {
|
if (res?._id) {
|
||||||
await interaction.reply('Channel unbridged.');
|
await interaction.reply("Channel unbridged.");
|
||||||
if (ownPerms.has('MANAGE_WEBHOOKS') && res.discordWebhook) {
|
if (
|
||||||
|
ownPerms.has("MANAGE_WEBHOOKS") &&
|
||||||
|
res.discordWebhook
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const hooks = await (interaction.channel as TextChannel).fetchWebhooks();
|
const hooks = await(
|
||||||
if (hooks.get(res?.discordWebhook?.id)) await hooks.get(res?.discordWebhook?.id)
|
interaction.channel as TextChannel
|
||||||
?.delete('Channel has been unbridged');
|
).fetchWebhooks();
|
||||||
} catch(_) {}
|
if (hooks.get(res?.discordWebhook?.id))
|
||||||
|
await hooks
|
||||||
|
.get(res?.discordWebhook?.id)
|
||||||
|
?.delete(
|
||||||
|
"Channel has been unbridged"
|
||||||
|
);
|
||||||
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
else await interaction.reply('This channel is not bridged.');
|
await interaction.reply(
|
||||||
|
"This channel is not bridged."
|
||||||
|
);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'help':
|
case "config": {
|
||||||
const isPrivileged = !!interaction.memberPermissions?.has('MANAGE_GUILD');
|
const configKey = interaction.options.getString(
|
||||||
|
"key",
|
||||||
|
true
|
||||||
|
) as keyof typeof CONFIG_KEYS;
|
||||||
|
const newValue = interaction.options.getBoolean(
|
||||||
|
"value",
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
if (newValue == null) {
|
||||||
|
const currentState =
|
||||||
|
(
|
||||||
|
await BRIDGE_CONFIG.findOne({
|
||||||
|
discord: interaction.channelId,
|
||||||
|
})
|
||||||
|
)?.config?.[configKey] ?? false;
|
||||||
|
|
||||||
|
return await interaction.reply({
|
||||||
|
ephemeral: true,
|
||||||
|
embeds: [
|
||||||
|
new MessageEmbed()
|
||||||
|
.setAuthor({
|
||||||
|
name: "Bridge Configuration",
|
||||||
|
})
|
||||||
|
.setTitle(configKey)
|
||||||
|
.setDescription(
|
||||||
|
`${CONFIG_KEYS[configKey].description}\n\nCurrent state: \`${currentState}\``
|
||||||
|
)
|
||||||
|
.toJSON(),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await BRIDGE_CONFIG.update(
|
||||||
|
{ discord: interaction.channelId },
|
||||||
|
{
|
||||||
|
$set: { [`config.${configKey}`]: newValue },
|
||||||
|
$setOnInsert: {
|
||||||
|
discord: interaction.channelId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ upsert: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
return await interaction.reply({
|
||||||
|
ephemeral: true,
|
||||||
|
content: `Option \`${configKey}\` has been updated to \`${newValue}\`.`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
case "help": {
|
||||||
|
const isPrivileged =
|
||||||
|
!!interaction.memberPermissions?.has(
|
||||||
|
"MANAGE_GUILD"
|
||||||
|
);
|
||||||
const INVITE_URL = `https://discord.com/api/oauth2/authorize?client_id=${client.user?.id}&permissions=536996864&scope=bot%20applications.commands`;
|
const INVITE_URL = `https://discord.com/api/oauth2/authorize?client_id=${client.user?.id}&permissions=536996864&scope=bot%20applications.commands`;
|
||||||
const embed = new MessageEmbed()
|
const embed = new MessageEmbed()
|
||||||
.setColor('#ff6e6d')
|
.setColor("#ff6e6d")
|
||||||
.setAuthor({ name: 'AutoMod Revolt Bridge', iconURL: client.user?.displayAvatarURL() });
|
.setAuthor({
|
||||||
|
name: "AutoMod Revolt Bridge",
|
||||||
|
iconURL: client.user?.displayAvatarURL(),
|
||||||
|
});
|
||||||
|
|
||||||
embed.setDescription(
|
embed.setDescription(
|
||||||
'[AutoMod](https://automod.me) is a utility and moderation bot for [Revolt](https://revolt.chat). ' +
|
"[AutoMod](https://automod.me) is a utility and moderation bot for [Revolt](https://revolt.chat). " +
|
||||||
'This Discord bot allows you to link your Discord servers to your Revolt servers ' +
|
"This Discord bot allows you to link your Discord servers to your Revolt servers " +
|
||||||
'by mirroring messages between text channels.'
|
"by mirroring messages between text channels."
|
||||||
);
|
);
|
||||||
|
|
||||||
embed.addField(
|
embed.addField(
|
||||||
'Setting up a bridge',
|
"Setting up a bridge",
|
||||||
isPrivileged
|
isPrivileged
|
||||||
? 'The bridge process is initialized by running the `/bridge link` command in the Revolt ' +
|
? "The bridge process is initialized by running the `/bridge link` command in the Revolt " +
|
||||||
'channel you wish to bridge.\n' +
|
"channel you wish to bridge.\n" +
|
||||||
'Afterwards you can run the `/bridge confirm` command in the correct Discord channel to finish the link.'
|
"Afterwards you can run the `/bridge confirm` command in the correct Discord channel to finish the link."
|
||||||
: 'You don\'t have `Manage Messages` permission - Please ask a moderator to configure the bridge.'
|
: "You don't have `Manage Messages` permission - Please ask a moderator to configure the bridge."
|
||||||
);
|
);
|
||||||
|
|
||||||
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").`
|
||||||
);
|
);
|
||||||
|
|
||||||
embed.addField(
|
embed.addField(
|
||||||
'Contact',
|
"Contact",
|
||||||
`If you have any questions regarding this bot or the Revolt counterpart, feel free to join ` +
|
`If you have any questions regarding this bot or the Revolt counterpart, feel free to join ` +
|
||||||
`[this](https://discord.gg/4pZgvqgYJ8) Discord server or [this](https://rvlt.gg/jan) Revolt server.\n` +
|
`[this](https://discord.gg/4pZgvqgYJ8) Discord server or [this](https://rvlt.gg/jan) Revolt server.\n` +
|
||||||
`If you want to report a bug, suggest a feature or browse the source code, ` +
|
`If you want to report a bug, suggest a feature or browse the source code, ` +
|
||||||
|
@ -186,31 +317,45 @@ client.on('interactionCreate', async interaction => {
|
||||||
`Before using this bot, please read the [Privacy Policy](${PRIVACY_POLICY_URL})!`
|
`Before using this bot, please read the [Privacy Policy](${PRIVACY_POLICY_URL})!`
|
||||||
);
|
);
|
||||||
|
|
||||||
await interaction.reply({ embeds: [ embed ], ephemeral: true });
|
await interaction.reply({
|
||||||
|
embeds: [embed],
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'opt_out':
|
case "opt_out": {
|
||||||
const optOut = interaction.options.getBoolean('opt_out', false);
|
const optOut = interaction.options.getBoolean(
|
||||||
|
"opt_out",
|
||||||
|
false
|
||||||
|
);
|
||||||
if (optOut == null) {
|
if (optOut == null) {
|
||||||
const userConfig = await BRIDGE_USER_CONFIG.findOne({ id: interaction.user.id });
|
const userConfig =
|
||||||
|
await BRIDGE_USER_CONFIG.findOne({
|
||||||
|
id: interaction.user.id,
|
||||||
|
});
|
||||||
if (userConfig?.optOut) {
|
if (userConfig?.optOut) {
|
||||||
return await interaction.reply({
|
return await interaction.reply({
|
||||||
ephemeral: true,
|
ephemeral: true,
|
||||||
content: 'You are currently **opted out** of message bridging. ' +
|
content:
|
||||||
'Users on Revolt **will not** see your username, avatar or message content.'
|
"You are currently **opted out** of message bridging. " +
|
||||||
|
"Users on Revolt **will not** see your username, avatar or message content.",
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await interaction.reply({
|
return await interaction.reply({
|
||||||
ephemeral: true,
|
ephemeral: true,
|
||||||
content: 'You are currently **not** opted out of message bridging. ' +
|
content:
|
||||||
'All your messages in a bridged channel will be sent to the associated Revolt channel.'
|
"You are currently **not** opted out of message bridging. " +
|
||||||
|
"All your messages in a bridged channel will be sent to the associated Revolt channel.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await BRIDGE_USER_CONFIG.update(
|
await BRIDGE_USER_CONFIG.update(
|
||||||
{ id: interaction.user.id },
|
{ id: interaction.user.id },
|
||||||
{
|
{
|
||||||
$setOnInsert: { id: interaction.user.id },
|
$setOnInsert: {
|
||||||
|
id: interaction.user.id,
|
||||||
|
},
|
||||||
$set: { optOut },
|
$set: { optOut },
|
||||||
},
|
},
|
||||||
{ upsert: true }
|
{ upsert: true }
|
||||||
|
@ -218,104 +363,135 @@ client.on('interactionCreate', async interaction => {
|
||||||
|
|
||||||
return await interaction.reply({
|
return await interaction.reply({
|
||||||
ephemeral: true,
|
ephemeral: true,
|
||||||
content: `You have **opted ${optOut ? 'out of' : 'into'}** message bridging. `
|
content:
|
||||||
+ (
|
`You have **opted ${
|
||||||
optOut
|
optOut ? "out of" : "into"
|
||||||
? 'Your username, avatar and message content will no longer be visible on Revolt.\n' +
|
}** message bridging. ` +
|
||||||
'Please note that some servers may be configured to automatically delete your messages.'
|
(optOut
|
||||||
: 'All your messages in a bridged channel will be sent to the associated Revolt channel.'
|
? "Your username, avatar and message content will no longer be visible on Revolt.\n" +
|
||||||
),
|
"Please note that some servers may be configured to automatically delete your messages."
|
||||||
|
: "All your messages in a bridged channel will be sent to the associated Revolt channel."),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
|
||||||
case 'status':
|
case "status": {
|
||||||
const bridgeConfig = await BRIDGE_CONFIG.findOne({ discord: interaction.channelId });
|
const bridgeConfig = await BRIDGE_CONFIG.findOne({
|
||||||
|
discord: interaction.channelId,
|
||||||
|
});
|
||||||
|
|
||||||
if (!bridgeConfig?.revolt) {
|
if (!bridgeConfig?.revolt) {
|
||||||
return await interaction.reply({
|
return await interaction.reply({
|
||||||
ephemeral: true,
|
ephemeral: true,
|
||||||
content: 'This channel is **not** bridged. No message content data will be processed.',
|
content:
|
||||||
|
"This channel is **not** bridged. No message content data will be processed.",
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return await interaction.reply({
|
return await interaction.reply({
|
||||||
ephemeral: true,
|
ephemeral: true,
|
||||||
content: 'This channel is **bridged to Revolt**. Your messages will ' +
|
content:
|
||||||
'be processed and sent to [Revolt](<https://revolt.chat>) according to AutoMod\'s ' +
|
"This channel is **bridged to Revolt**. Your messages will " +
|
||||||
|
"be processed and sent to [Revolt](<https://revolt.chat>) according to AutoMod's " +
|
||||||
`[Privacy Policy](<${PRIVACY_POLICY_URL}>).`,
|
`[Privacy Policy](<${PRIVACY_POLICY_URL}>).`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default: await interaction.reply('Unknown subcommand');
|
default:
|
||||||
|
await interaction.reply("Unknown subcommand");
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} else if (interaction.isMessageContextMenu()) {
|
||||||
else if (interaction.isMessageContextMenu()) {
|
logger.debug(
|
||||||
logger.debug(`Received context menu: ${interaction.targetMessage.id}`);
|
`Received context menu: ${interaction.targetMessage.id}`
|
||||||
|
);
|
||||||
|
|
||||||
switch(interaction.commandName) {
|
switch (interaction.commandName) {
|
||||||
case 'Message Info':
|
case "Message Info":
|
||||||
const message = interaction.targetMessage;
|
const message = interaction.targetMessage;
|
||||||
const bridgeInfo = await BRIDGED_MESSAGES.findOne({ "discord.messageId": message.id });
|
const bridgeInfo = await BRIDGED_MESSAGES.findOne({
|
||||||
|
"discord.messageId": message.id,
|
||||||
|
});
|
||||||
const messageUrl = `https://discord.com/channels/${interaction.guildId}/${interaction.channelId}/${message.id}`;
|
const messageUrl = `https://discord.com/channels/${interaction.guildId}/${interaction.channelId}/${message.id}`;
|
||||||
|
|
||||||
if (!bridgeInfo) return await interaction.reply({
|
if (!bridgeInfo)
|
||||||
|
return await interaction.reply({
|
||||||
ephemeral: true,
|
ephemeral: true,
|
||||||
embeds: [
|
embeds: [
|
||||||
new MessageEmbed()
|
new MessageEmbed()
|
||||||
.setAuthor({ name: 'Message info', url: messageUrl })
|
.setAuthor({
|
||||||
.setDescription('This message has not been bridged.')
|
name: "Message info",
|
||||||
.setColor('#7e96ff'),
|
url: messageUrl,
|
||||||
|
})
|
||||||
|
.setDescription(
|
||||||
|
"This message has not been bridged."
|
||||||
|
)
|
||||||
|
.setColor("#7e96ff"),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
else {
|
else {
|
||||||
const embed = new MessageEmbed();
|
const embed = new MessageEmbed();
|
||||||
|
|
||||||
embed.setColor('#7e96ff');
|
embed.setColor("#7e96ff");
|
||||||
embed.setAuthor({ name: 'Message info', url: messageUrl });
|
embed.setAuthor({
|
||||||
|
name: "Message info",
|
||||||
|
url: messageUrl,
|
||||||
|
});
|
||||||
|
|
||||||
embed.addField('Origin', bridgeInfo.origin == 'discord' ? 'Discord' : 'Revolt', true);
|
|
||||||
|
|
||||||
if (bridgeInfo.origin == 'discord') {
|
|
||||||
embed.addField(
|
embed.addField(
|
||||||
'Bridge Status',
|
"Origin",
|
||||||
|
bridgeInfo.origin == "discord"
|
||||||
|
? "Discord"
|
||||||
|
: "Revolt",
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
if (bridgeInfo.origin == "discord") {
|
||||||
|
embed.addField(
|
||||||
|
"Bridge Status",
|
||||||
bridgeInfo.revolt.messageId
|
bridgeInfo.revolt.messageId
|
||||||
? 'Bridged'
|
? "Bridged"
|
||||||
: bridgeInfo.revolt.nonce
|
: bridgeInfo.revolt.nonce
|
||||||
? 'ID unknown'
|
? "ID unknown"
|
||||||
: 'Unbridged',
|
: "Unbridged",
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
embed.addField(
|
embed.addField(
|
||||||
'Bridge Status',
|
"Bridge Status",
|
||||||
bridgeInfo.discord.messageId
|
bridgeInfo.discord.messageId
|
||||||
? 'Bridged'
|
? "Bridged"
|
||||||
: 'Unbridged',
|
: "Unbridged",
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
if (bridgeInfo.channels?.revolt) {
|
if (bridgeInfo.channels?.revolt) {
|
||||||
const channel = await revoltClient.channels.get(bridgeInfo.channels.revolt);
|
const channel = await revoltClient.channels.get(
|
||||||
const revoltMsg = await revoltFetchMessage(bridgeInfo.revolt.messageId, channel);
|
bridgeInfo.channels.revolt
|
||||||
|
);
|
||||||
|
const revoltMsg = await revoltFetchMessage(
|
||||||
|
bridgeInfo.revolt.messageId,
|
||||||
|
channel
|
||||||
|
);
|
||||||
|
|
||||||
if (revoltMsg) {
|
if (revoltMsg) {
|
||||||
const author = await revoltFetchUser(revoltMsg.author_id);
|
const author = await revoltFetchUser(
|
||||||
|
revoltMsg.author_id
|
||||||
|
);
|
||||||
embed.addField(
|
embed.addField(
|
||||||
'Message Author',
|
"Message Author",
|
||||||
`**@${author?.username}** (${revoltMsg.author_id})`,
|
`**@${author?.username}** (${revoltMsg.author_id})`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
embed.addField(
|
embed.addField(
|
||||||
'Bridge Data',
|
"Bridge Data",
|
||||||
`Origin: \`${bridgeInfo.origin}\`\n` +
|
`Origin: \`${bridgeInfo.origin}\`\n` +
|
||||||
`Discord ID: \`${bridgeInfo.discord.messageId}\`\n` +
|
`Discord ID: \`${bridgeInfo.discord.messageId}\`\n` +
|
||||||
`Revolt ID: \`${bridgeInfo.revolt.messageId}\`\n` +
|
`Revolt ID: \`${bridgeInfo.revolt.messageId}\`\n` +
|
||||||
|
@ -326,13 +502,14 @@ client.on('interactionCreate', async interaction => {
|
||||||
|
|
||||||
return await interaction.reply({
|
return await interaction.reply({
|
||||||
ephemeral: true,
|
ephemeral: true,
|
||||||
embeds: [ embed ],
|
embeds: [embed],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
if (interaction.isCommand()) interaction.reply('An error has occurred: ' + e).catch(() => {});
|
if (interaction.isCommand())
|
||||||
|
interaction.reply("An error has occurred: " + e).catch(() => {});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -192,18 +192,24 @@ client.on('messageCreate', async message => {
|
||||||
//attachments: [],
|
//attachments: [],
|
||||||
//embeds: [],
|
//embeds: [],
|
||||||
nonce: nonce,
|
nonce: nonce,
|
||||||
replies: reply ? [ { id: reply, mention: !!message.mentions.repliedUser } ] : undefined,
|
replies: reply
|
||||||
|
? [{ id: reply, mention: !!message.mentions.repliedUser }]
|
||||||
|
: undefined,
|
||||||
masquerade: {
|
masquerade: {
|
||||||
name: message.author.username,
|
name: bridgeCfg.config?.bridge_nicknames
|
||||||
avatar: message.author.displayAvatarURL({ size: 128 }),
|
? message.member?.nickname ?? message.author.username
|
||||||
colour: channel.server?.havePermission('ManageRole')
|
: message.author.username,
|
||||||
|
avatar: bridgeCfg.config?.bridge_nicknames
|
||||||
|
? message.member?.displayAvatarURL({ size: 128 })
|
||||||
|
: message.author.displayAvatarURL({ size: 128 }),
|
||||||
|
colour: channel.server?.havePermission("ManageRole")
|
||||||
? message.member?.displayColor // Discord.js returns black or 0 instead of undefined when no role color is set
|
? message.member?.displayColor // Discord.js returns black or 0 instead of undefined when no role color is set
|
||||||
? message.member?.displayHexColor
|
? message.member?.displayHexColor
|
||||||
: 'var(--foreground)'
|
: "var(--foreground)"
|
||||||
: undefined,
|
: undefined,
|
||||||
},
|
},
|
||||||
embeds: message.embeds.length
|
embeds: message.embeds.length
|
||||||
? message.embeds.map(e => new GenericEmbed(e).toRevolt())
|
? message.embeds.map((e) => new GenericEmbed(e).toRevolt())
|
||||||
: undefined,
|
: undefined,
|
||||||
attachments: autumnUrls.length ? autumnUrls : undefined,
|
attachments: autumnUrls.length ? autumnUrls : undefined,
|
||||||
};
|
};
|
||||||
|
|
|
@ -150,16 +150,29 @@ client.on('message', async message => {
|
||||||
token: bridgeCfg.discordWebhook!.token,
|
token: bridgeCfg.discordWebhook!.token,
|
||||||
});
|
});
|
||||||
|
|
||||||
const payload: MessagePayload|WebhookMessageOptions = {
|
const payload: MessagePayload | WebhookMessageOptions = {
|
||||||
content: message.content ? await renderMessageBody(message.content) : undefined,
|
content: message.content
|
||||||
username: message.author?.username ?? 'Unknown user',
|
? await renderMessageBody(message.content)
|
||||||
avatarURL: message.author?.generateAvatarURL({ max_side: 128 }),
|
: undefined,
|
||||||
|
username:
|
||||||
|
(bridgeCfg.config?.bridge_nicknames
|
||||||
|
? message.masquerade?.name ??
|
||||||
|
message.member?.nickname ??
|
||||||
|
message.author?.username
|
||||||
|
: message.author?.username) ?? "Unknown user",
|
||||||
|
avatarURL: bridgeCfg.config?.bridge_nicknames
|
||||||
|
? message.masquerade?.avatar ??
|
||||||
|
message.member?.generateAvatarURL({ max_side: 128 }) ??
|
||||||
|
message.author?.generateAvatarURL({ max_side: 128 })
|
||||||
|
: message.author?.generateAvatarURL({ max_side: 128 }),
|
||||||
embeds: message.embeds?.length
|
embeds: message.embeds?.length
|
||||||
? message.embeds
|
? message.embeds
|
||||||
.filter(e => e.type == "Text")
|
.filter((e) => e.type == "Text")
|
||||||
.map(e => new GenericEmbed(e as SendableEmbed).toDiscord())
|
.map((e) =>
|
||||||
|
new GenericEmbed(e as SendableEmbed).toDiscord()
|
||||||
|
)
|
||||||
: undefined,
|
: undefined,
|
||||||
allowedMentions: { parse: [ ] },
|
allowedMentions: { parse: [] },
|
||||||
};
|
};
|
||||||
|
|
||||||
if (repliedMessages.length) {
|
if (repliedMessages.length) {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { CONFIG_KEYS } from "./ConfigKeys";
|
||||||
|
|
||||||
export default class {
|
export default class {
|
||||||
// Revolt channel ID
|
// Revolt channel ID
|
||||||
revolt?: string;
|
revolt?: string;
|
||||||
|
@ -9,7 +11,9 @@ export default class {
|
||||||
discordWebhook?: {
|
discordWebhook?: {
|
||||||
id: string;
|
id: string;
|
||||||
token: string;
|
token: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
config?: { [key in keyof typeof CONFIG_KEYS]: boolean | undefined };
|
||||||
|
|
||||||
// If true, messages by users who have opted out of bridging will be deleted.
|
// If true, messages by users who have opted out of bridging will be deleted.
|
||||||
disallowIfOptedOut?: boolean;
|
disallowIfOptedOut?: boolean;
|
||||||
|
|
13
bridge/src/types/ConfigKeys.ts
Normal file
13
bridge/src/types/ConfigKeys.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
export const CONFIG_KEYS = {
|
||||||
|
bridge_nicknames: {
|
||||||
|
friendlyName: "Bridge Nicknames",
|
||||||
|
description:
|
||||||
|
"If enabled, nicknames and avatar overrides will be bridged.",
|
||||||
|
},
|
||||||
|
// disallow_opt_out: {
|
||||||
|
// friendlyName: "Disallow users who opted out of message bridging",
|
||||||
|
// description:
|
||||||
|
// "If enabled, all messages by users who opted out of their messages being bridged (`/bridge opt_out`) will be deleted. " +
|
||||||
|
// "You should enable this if your Revolt server is bridged to a mostly unmoderated Discord server.",
|
||||||
|
// },
|
||||||
|
};
|
Loading…
Reference in a new issue