bridge system messages revolt -> discord
This commit is contained in:
parent
e71a02eb9b
commit
1ab0dff37d
2 changed files with 301 additions and 112 deletions
|
@ -3,8 +3,13 @@ import { AUTUMN_URL, client } from "./client";
|
||||||
import { client as discordClient } from "../discord/client";
|
import { client as discordClient } from "../discord/client";
|
||||||
import { Channel as DiscordChannel, Message as DiscordMessage, MessageEmbed, MessagePayload, TextChannel, WebhookClient, WebhookMessageOptions } from "discord.js";
|
import { Channel as DiscordChannel, Message as DiscordMessage, MessageEmbed, MessagePayload, TextChannel, WebhookClient, WebhookMessageOptions } from "discord.js";
|
||||||
import GenericEmbed from "../types/GenericEmbed";
|
import GenericEmbed from "../types/GenericEmbed";
|
||||||
import { SendableEmbed } from "revolt-api";
|
import { SendableEmbed, SystemMessage } from "revolt-api";
|
||||||
import { clipText, discordFetchMessage, revoltFetchMessage, revoltFetchUser } from "../util";
|
import {
|
||||||
|
clipText,
|
||||||
|
discordFetchMessage,
|
||||||
|
revoltFetchMessage,
|
||||||
|
revoltFetchUser,
|
||||||
|
} from "../util";
|
||||||
import { smartReplace } from "smart-replace";
|
import { smartReplace } from "smart-replace";
|
||||||
import { metrics } from "../metrics";
|
import { metrics } from "../metrics";
|
||||||
import { fetchEmojiList } from "../discord/bridgeEmojis";
|
import { fetchEmojiList } from "../discord/bridgeEmojis";
|
||||||
|
@ -16,42 +21,70 @@ const RE_EMOJI = /:[^\s]+/g;
|
||||||
const KNOWN_EMOJI_NAMES: string[] = [];
|
const KNOWN_EMOJI_NAMES: string[] = [];
|
||||||
|
|
||||||
fetchEmojiList()
|
fetchEmojiList()
|
||||||
.then(emojis => Object.keys(emojis).forEach(name => KNOWN_EMOJI_NAMES.push(name)))
|
.then((emojis) =>
|
||||||
.catch(e => console.error(e));
|
Object.keys(emojis).forEach((name) => KNOWN_EMOJI_NAMES.push(name))
|
||||||
|
)
|
||||||
|
.catch((e) => console.error(e));
|
||||||
|
|
||||||
client.on('message/delete', async id => {
|
client.on("message/delete", async (id) => {
|
||||||
try {
|
try {
|
||||||
logger.debug(`[D] Revolt: ${id}`);
|
logger.debug(`[D] Revolt: ${id}`);
|
||||||
|
|
||||||
const bridgedMsg = await BRIDGED_MESSAGES.findOne({ "revolt.messageId": id });
|
const bridgedMsg = await BRIDGED_MESSAGES.findOne({
|
||||||
if (!bridgedMsg?.discord.messageId) return logger.debug(`Revolt: Message has not been bridged; ignoring delete`);
|
"revolt.messageId": id,
|
||||||
if (!bridgedMsg.channels?.discord) return logger.debug(`Revolt: Channel for deleted message is unknown`);
|
});
|
||||||
|
if (!bridgedMsg?.discord.messageId)
|
||||||
|
return logger.debug(
|
||||||
|
`Revolt: Message has not been bridged; ignoring delete`
|
||||||
|
);
|
||||||
|
if (!bridgedMsg.channels?.discord)
|
||||||
|
return logger.debug(
|
||||||
|
`Revolt: Channel for deleted message is unknown`
|
||||||
|
);
|
||||||
|
|
||||||
const bridgeCfg = await BRIDGE_CONFIG.findOne({ revolt: bridgedMsg.channels.revolt });
|
const bridgeCfg = await BRIDGE_CONFIG.findOne({
|
||||||
if (!bridgeCfg?.discordWebhook) return logger.debug(`Revolt: No Discord webhook stored`);
|
revolt: bridgedMsg.channels.revolt,
|
||||||
if (!bridgeCfg.discord || bridgeCfg.discord != bridgedMsg.channels.discord) {
|
});
|
||||||
return logger.debug(`Revolt: Discord channel is no longer linked; ignoring delete`);
|
if (!bridgeCfg?.discordWebhook)
|
||||||
|
return logger.debug(`Revolt: No Discord webhook stored`);
|
||||||
|
if (
|
||||||
|
!bridgeCfg.discord ||
|
||||||
|
bridgeCfg.discord != bridgedMsg.channels.discord
|
||||||
|
) {
|
||||||
|
return logger.debug(
|
||||||
|
`Revolt: Discord channel is no longer linked; ignoring delete`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetMsg = await discordFetchMessage(bridgedMsg.discord.messageId, bridgeCfg.discord);
|
const targetMsg = await discordFetchMessage(
|
||||||
if (!targetMsg) return logger.debug(`Revolt: Could not fetch message from Discord`);
|
bridgedMsg.discord.messageId,
|
||||||
|
bridgeCfg.discord
|
||||||
|
);
|
||||||
|
if (!targetMsg)
|
||||||
|
return logger.debug(`Revolt: Could not fetch message from Discord`);
|
||||||
|
|
||||||
if (targetMsg.webhookId && targetMsg.webhookId == bridgeCfg.discordWebhook.id) {
|
if (
|
||||||
const client = new WebhookClient({ id: bridgeCfg.discordWebhook.id, token: bridgeCfg.discordWebhook.token });
|
targetMsg.webhookId &&
|
||||||
|
targetMsg.webhookId == bridgeCfg.discordWebhook.id
|
||||||
|
) {
|
||||||
|
const client = new WebhookClient({
|
||||||
|
id: bridgeCfg.discordWebhook.id,
|
||||||
|
token: bridgeCfg.discordWebhook.token,
|
||||||
|
});
|
||||||
await client.deleteMessage(bridgedMsg.discord.messageId);
|
await client.deleteMessage(bridgedMsg.discord.messageId);
|
||||||
client.destroy();
|
client.destroy();
|
||||||
metrics.messages.inc({ source: 'revolt', type: 'delete' });
|
metrics.messages.inc({ source: "revolt", type: "delete" });
|
||||||
} else if (targetMsg.deletable) {
|
} else if (targetMsg.deletable) {
|
||||||
targetMsg.delete();
|
targetMsg.delete();
|
||||||
metrics.messages.inc({ source: 'revolt', type: 'delete' });
|
metrics.messages.inc({ source: "revolt", type: "delete" });
|
||||||
} else logger.debug(`Revolt: Unable to delete Discord message`);
|
} else logger.debug(`Revolt: Unable to delete Discord message`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('message/update', async message => {
|
client.on("message/update", 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.author_id == client.user?._id) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -62,69 +95,116 @@ client.on('message/update', async message => {
|
||||||
BRIDGED_MESSAGES.findOne({ "revolt.nonce": message.nonce }),
|
BRIDGED_MESSAGES.findOne({ "revolt.nonce": message.nonce }),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (!bridgedMsg) return logger.debug(`Revolt: Message has not been bridged; ignoring edit`);
|
if (!bridgedMsg)
|
||||||
if (!bridgeCfg?.discord) return logger.debug(`Revolt: No Discord channel associated`);
|
return logger.debug(
|
||||||
if (!bridgeCfg.discordWebhook) return logger.debug(`Revolt: No Discord webhook stored`);
|
`Revolt: Message has not been bridged; ignoring edit`
|
||||||
|
);
|
||||||
|
if (!bridgeCfg?.discord)
|
||||||
|
return logger.debug(`Revolt: No Discord channel associated`);
|
||||||
|
if (!bridgeCfg.discordWebhook)
|
||||||
|
return logger.debug(`Revolt: No Discord webhook stored`);
|
||||||
|
|
||||||
const targetMsg = await discordFetchMessage(bridgedMsg.discord.messageId, bridgeCfg.discord);
|
const targetMsg = await discordFetchMessage(
|
||||||
if (!targetMsg) return logger.debug(`Revolt: Could not fetch message from Discord`);
|
bridgedMsg.discord.messageId,
|
||||||
|
bridgeCfg.discord
|
||||||
|
);
|
||||||
|
if (!targetMsg)
|
||||||
|
return logger.debug(`Revolt: Could not fetch message from Discord`);
|
||||||
|
|
||||||
const client = new WebhookClient({ id: bridgeCfg.discordWebhook.id, token: bridgeCfg.discordWebhook.token });
|
const client = new WebhookClient({
|
||||||
await client.editMessage(targetMsg, { content: await renderMessageBody(message.content), allowedMentions: { parse: [ ] } });
|
id: bridgeCfg.discordWebhook.id,
|
||||||
|
token: bridgeCfg.discordWebhook.token,
|
||||||
|
});
|
||||||
|
await client.editMessage(targetMsg, {
|
||||||
|
content: await renderMessageBody(message.content),
|
||||||
|
allowedMentions: { parse: [] },
|
||||||
|
});
|
||||||
client.destroy();
|
client.destroy();
|
||||||
|
|
||||||
metrics.messages.inc({ source: 'revolt', type: 'edit' });
|
metrics.messages.inc({ source: "revolt", type: "edit" });
|
||||||
} catch(e) { console.error(e) }
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('message', async message => {
|
client.on("message", async (message) => {
|
||||||
try {
|
try {
|
||||||
if (message.content && typeof message.content != 'string') return;
|
logger.debug(`[M] Revolt: ${message._id} ${message.content}`);
|
||||||
logger.debug(`[M] Revolt: ${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.channel_id }),
|
||||||
BRIDGED_MESSAGES.findOne({ "revolt.nonce": message.nonce }),
|
BRIDGED_MESSAGES.findOne(
|
||||||
...(message.reply_ids?.map(id => BRIDGED_MESSAGES.findOne({ "revolt.messageId": id })) ?? [])
|
message.nonce
|
||||||
|
? { "revolt.nonce": message.nonce }
|
||||||
|
: { "revolt.messageId": message._id }
|
||||||
|
),
|
||||||
|
...(message.reply_ids?.map((id) =>
|
||||||
|
BRIDGED_MESSAGES.findOne({ "revolt.messageId": id })
|
||||||
|
) ?? []),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (bridgedMsg) return logger.debug(`Revolt: Message has already been bridged; ignoring`);
|
if (bridgedMsg)
|
||||||
if (!bridgeCfg?.discord) return logger.debug(`Revolt: No Discord channel associated`);
|
return logger.debug(
|
||||||
|
`Revolt: Message has already been bridged; ignoring`
|
||||||
|
);
|
||||||
|
if (message.system && bridgeCfg?.config?.disable_system_messages)
|
||||||
|
return logger.debug(
|
||||||
|
`Revolt: System message bridging disabled; ignoring`
|
||||||
|
);
|
||||||
|
if (!bridgeCfg?.discord)
|
||||||
|
return logger.debug(`Revolt: No Discord channel associated`);
|
||||||
if (!bridgeCfg.discordWebhook) {
|
if (!bridgeCfg.discordWebhook) {
|
||||||
logger.debug(`Revolt: No Discord webhook stored; Creating new Webhook`);
|
logger.debug(
|
||||||
|
`Revolt: No Discord webhook stored; Creating new Webhook`
|
||||||
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const channel = await discordClient.channels.fetch(bridgeCfg.discord) as TextChannel;
|
const channel = (await discordClient.channels.fetch(
|
||||||
if (!channel || !channel.isText()) throw 'Error: Unable to fetch channel';
|
bridgeCfg.discord
|
||||||
const ownPerms = (channel as TextChannel).permissionsFor(discordClient.user!);
|
)) as TextChannel;
|
||||||
if (!ownPerms?.has('MANAGE_WEBHOOKS')) throw 'Error: Bot user does not have MANAGE_WEBHOOKS permission';
|
if (!channel || !channel.isText())
|
||||||
|
throw "Error: Unable to fetch channel";
|
||||||
|
const ownPerms = (channel as TextChannel).permissionsFor(
|
||||||
|
discordClient.user!
|
||||||
|
);
|
||||||
|
if (!ownPerms?.has("MANAGE_WEBHOOKS"))
|
||||||
|
throw "Error: Bot user does not have MANAGE_WEBHOOKS permission";
|
||||||
|
|
||||||
const hook = await (channel as TextChannel).createWebhook('AutoMod Bridge', { avatar: discordClient.user?.avatarURL() });
|
const hook = await (channel as TextChannel).createWebhook(
|
||||||
|
"AutoMod Bridge",
|
||||||
|
{ avatar: discordClient.user?.avatarURL() }
|
||||||
|
);
|
||||||
|
|
||||||
bridgeCfg.discordWebhook = {
|
bridgeCfg.discordWebhook = {
|
||||||
id: hook.id,
|
id: hook.id,
|
||||||
token: hook.token || '',
|
token: hook.token || "",
|
||||||
};
|
};
|
||||||
await BRIDGE_CONFIG.update(
|
await BRIDGE_CONFIG.update(
|
||||||
{ revolt: message.channel_id },
|
{ revolt: message.channel_id },
|
||||||
{
|
{
|
||||||
$set: {
|
$set: {
|
||||||
discordWebhook: bridgeCfg.discordWebhook,
|
discordWebhook: bridgeCfg.discordWebhook,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.warn(`Unable to create new webhook for channel ${bridgeCfg.discord}; Deleting link\n${e}`);
|
logger.warn(
|
||||||
|
`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.channel_id });
|
||||||
await message.channel?.sendMessage(':warning: I was unable to create a webhook in the bridged Discord channel. '
|
await message.channel
|
||||||
+ `The bridge has been removed; if you wish to rebridge, use the \`/bridge\` command.`).catch(() => {});
|
?.sendMessage(
|
||||||
|
":warning: I was unable to create a webhook in the bridged Discord channel. " +
|
||||||
|
`The bridge has been removed; if you wish to rebridge, use the \`/bridge\` command.`
|
||||||
|
)
|
||||||
|
.catch(() => {});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await BRIDGED_MESSAGES.update(
|
await BRIDGED_MESSAGES.update(
|
||||||
{ 'revolt.messageId': message._id },
|
{ "revolt.messageId": message._id },
|
||||||
{
|
{
|
||||||
$set: {
|
$set: {
|
||||||
revolt: {
|
revolt: {
|
||||||
|
@ -134,33 +214,41 @@ client.on('message', async message => {
|
||||||
channels: {
|
channels: {
|
||||||
revolt: message.channel_id,
|
revolt: message.channel_id,
|
||||||
discord: bridgeCfg.discord,
|
discord: bridgeCfg.discord,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
$setOnInsert: {
|
$setOnInsert: {
|
||||||
discord: {},
|
discord: {},
|
||||||
origin: 'revolt',
|
origin: "revolt",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{ upsert: true }
|
{ upsert: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
const channel = await discordClient.channels.fetch(bridgeCfg.discord) as TextChannel;
|
const channel = (await discordClient.channels.fetch(
|
||||||
|
bridgeCfg.discord
|
||||||
|
)) as TextChannel;
|
||||||
const client = new WebhookClient({
|
const client = new WebhookClient({
|
||||||
id: bridgeCfg.discordWebhook!.id,
|
id: bridgeCfg.discordWebhook!.id,
|
||||||
token: bridgeCfg.discordWebhook!.token,
|
token: bridgeCfg.discordWebhook!.token,
|
||||||
});
|
});
|
||||||
|
|
||||||
const payload: MessagePayload | WebhookMessageOptions = {
|
const payload: MessagePayload | WebhookMessageOptions = {
|
||||||
content: message.content
|
content:
|
||||||
|
typeof message.content == "string"
|
||||||
? await renderMessageBody(message.content)
|
? await renderMessageBody(message.content)
|
||||||
|
: message.system
|
||||||
|
? await renderSystemMessage(message.system)
|
||||||
: undefined,
|
: undefined,
|
||||||
username:
|
username: message.system
|
||||||
(bridgeCfg.config?.bridge_nicknames
|
? "Revolt"
|
||||||
|
: (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: bridgeCfg.config?.bridge_nicknames
|
avatarURL: message.system
|
||||||
|
? "https://app.revolt.chat/assets/logo_round.png"
|
||||||
|
: bridgeCfg.config?.bridge_nicknames
|
||||||
? message.masquerade?.avatar ??
|
? message.masquerade?.avatar ??
|
||||||
message.member?.generateAvatarURL({ max_side: 128 }) ??
|
message.member?.generateAvatarURL({ max_side: 128 }) ??
|
||||||
message.author?.generateAvatarURL({ max_side: 128 })
|
message.author?.generateAvatarURL({ max_side: 128 })
|
||||||
|
@ -176,54 +264,94 @@ client.on('message', async message => {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (repliedMessages.length) {
|
if (repliedMessages.length) {
|
||||||
const embed = new MessageEmbed().setColor('#2f3136');
|
const embed = new MessageEmbed().setColor("#2f3136");
|
||||||
|
|
||||||
if (repliedMessages.length == 1) {
|
if (repliedMessages.length == 1) {
|
||||||
const replyMsg = repliedMessages[0]?.origin == 'discord'
|
const replyMsg =
|
||||||
? await discordFetchMessage(repliedMessages[0]?.discord.messageId, bridgeCfg.discord)
|
repliedMessages[0]?.origin == "discord"
|
||||||
|
? await discordFetchMessage(
|
||||||
|
repliedMessages[0]?.discord.messageId,
|
||||||
|
bridgeCfg.discord
|
||||||
|
)
|
||||||
: undefined;
|
: undefined;
|
||||||
const author = replyMsg?.author;
|
const author = replyMsg?.author;
|
||||||
|
|
||||||
if (replyMsg) {
|
if (replyMsg) {
|
||||||
embed.setAuthor({
|
embed.setAuthor({
|
||||||
name: `@${author?.username ?? 'Unknown'}`, // todo: check if @pinging was enabled for reply
|
name: `@${author?.username ?? "Unknown"}`, // todo: check if @pinging was enabled for reply
|
||||||
iconURL: author?.displayAvatarURL({ size: 64, dynamic: true }),
|
iconURL: author?.displayAvatarURL({
|
||||||
|
size: 64,
|
||||||
|
dynamic: true,
|
||||||
|
}),
|
||||||
url: replyMsg?.url,
|
url: replyMsg?.url,
|
||||||
});
|
});
|
||||||
if (replyMsg?.content) embed.setDescription('>>> ' + clipText(replyMsg.content, 200));
|
if (replyMsg?.content)
|
||||||
|
embed.setDescription(
|
||||||
|
">>> " + clipText(replyMsg.content, 200)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
const msg = await revoltFetchMessage(message.reply_ids?.[0], message.channel);
|
const msg = await revoltFetchMessage(
|
||||||
const brMsg = repliedMessages.find(m => m?.revolt.messageId == msg?._id);
|
message.reply_ids?.[0],
|
||||||
|
message.channel
|
||||||
|
);
|
||||||
|
const brMsg = repliedMessages.find(
|
||||||
|
(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?.generateAvatarURL({ size: 64 }),
|
||||||
url: brMsg ? `https://discord.com/channels/${channel.guildId}/${brMsg.channels?.discord || channel.id}/${brMsg.discord.messageId}` : undefined,
|
url: brMsg
|
||||||
|
? `https://discord.com/channels/${
|
||||||
|
channel.guildId
|
||||||
|
}/${brMsg.channels?.discord || channel.id}/${
|
||||||
|
brMsg.discord.messageId
|
||||||
|
}`
|
||||||
|
: undefined,
|
||||||
});
|
});
|
||||||
if (msg?.content) embed.setDescription('>>> ' + clipText(msg.content, 200));
|
if (msg?.content)
|
||||||
|
embed.setDescription(
|
||||||
|
">>> " + clipText(msg.content, 200)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const replyMsgs = await Promise.all(
|
const replyMsgs = await Promise.all(
|
||||||
repliedMessages.map(m => m?.origin == 'discord'
|
repliedMessages.map((m) =>
|
||||||
? discordFetchMessage(m?.discord.messageId, bridgeCfg.discord)
|
m?.origin == "discord"
|
||||||
: revoltFetchMessage(m?.revolt.messageId, message.channel))
|
? discordFetchMessage(
|
||||||
|
m?.discord.messageId,
|
||||||
|
bridgeCfg.discord
|
||||||
|
)
|
||||||
|
: revoltFetchMessage(
|
||||||
|
m?.revolt.messageId,
|
||||||
|
message.channel
|
||||||
|
)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
embed.setAuthor({ name: repliedMessages.length + ' replies' });
|
embed.setAuthor({ name: repliedMessages.length + " replies" });
|
||||||
|
|
||||||
for (const msg of replyMsgs) {
|
for (const msg of replyMsgs) {
|
||||||
let msgUrl = '';
|
let msgUrl = "";
|
||||||
if (msg instanceof DiscordMessage) {
|
if (msg instanceof DiscordMessage) {
|
||||||
msgUrl = msg.url;
|
msgUrl = msg.url;
|
||||||
} else {
|
} else {
|
||||||
const brMsg = repliedMessages.find(m => m?.revolt.messageId == msg?._id);
|
const brMsg = repliedMessages.find(
|
||||||
if (brMsg) msgUrl = `https://discord.com/channels/${channel.guildId}/${brMsg.channels?.discord || channel.id}/${brMsg.discord.messageId}`;
|
(m) => m?.revolt.messageId == msg?._id
|
||||||
|
);
|
||||||
|
if (brMsg)
|
||||||
|
msgUrl = `https://discord.com/channels/${
|
||||||
|
channel.guildId
|
||||||
|
}/${brMsg.channels?.discord || channel.id}/${
|
||||||
|
brMsg.discord.messageId
|
||||||
|
}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
embed.addField(
|
embed.addField(
|
||||||
`@${msg?.author?.username ?? 'Unknown'}`,
|
`@${msg?.author?.username ?? "Unknown"}`,
|
||||||
(msg ? `[Link](${msgUrl})\n` : '') +
|
(msg ? `[Link](${msgUrl})\n` : "") +
|
||||||
'>>> ' + clipText(msg?.content ?? '\u200b', 100),
|
">>> " +
|
||||||
true,
|
clipText(msg?.content ?? "\u200b", 100),
|
||||||
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,24 +371,36 @@ client.on('message', async message => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
client.send(payload)
|
client
|
||||||
.then(async res => {
|
.send(payload)
|
||||||
await BRIDGED_MESSAGES.update({
|
.then(async (res) => {
|
||||||
"revolt.messageId": message._id
|
await BRIDGED_MESSAGES.update(
|
||||||
}, {
|
{
|
||||||
|
"revolt.messageId": message._id,
|
||||||
|
},
|
||||||
|
{
|
||||||
$set: {
|
$set: {
|
||||||
"discord.messageId": res.id
|
"discord.messageId": res.id,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
metrics.messages.inc({ source: 'revolt', type: 'create' });
|
metrics.messages.inc({ source: "revolt", type: "create" });
|
||||||
})
|
})
|
||||||
.catch(async e => {
|
.catch(async (e) => {
|
||||||
console.error('Failed to execute webhook:', e?.response?.data ?? e);
|
console.error(
|
||||||
if (`${e}` == 'DiscordAPIError: Unknown Webhook') {
|
"Failed to execute webhook:",
|
||||||
|
e?.response?.data ?? e
|
||||||
|
);
|
||||||
|
if (`${e}` == "DiscordAPIError: Unknown Webhook") {
|
||||||
try {
|
try {
|
||||||
logger.warn('Revolt: Got Unknown Webhook error, deleting webhook config');
|
logger.warn(
|
||||||
await BRIDGE_CONFIG.update({ revolt: message.channel_id }, { $set: { discordWebhook: undefined } });
|
"Revolt: Got Unknown Webhook error, deleting webhook config"
|
||||||
|
);
|
||||||
|
await BRIDGE_CONFIG.update(
|
||||||
|
{ revolt: message.channel_id },
|
||||||
|
{ $set: { discordWebhook: undefined } }
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
@ -352,3 +492,47 @@ async function renderMessageBody(message: string): Promise<string> {
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function renderSystemMessage(message: SystemMessage): Promise<string> {
|
||||||
|
const getUsername = async (id: string) =>
|
||||||
|
`**@${(await revoltFetchUser(id))?.username.replace(/\*/g, "\\*")}**`;
|
||||||
|
|
||||||
|
switch (message.type) {
|
||||||
|
case "user_joined":
|
||||||
|
case "user_added":
|
||||||
|
return `<:joined:1042831832888127509> ${await getUsername(
|
||||||
|
message.id
|
||||||
|
)} joined`;
|
||||||
|
case "user_left":
|
||||||
|
case "user_remove":
|
||||||
|
return `<:left:1042831834259652628> ${await getUsername(
|
||||||
|
message.id
|
||||||
|
)} left`;
|
||||||
|
case "user_kicked":
|
||||||
|
return `<:kicked:1042831835421483050> ${await getUsername(
|
||||||
|
message.id
|
||||||
|
)} was kicked`;
|
||||||
|
case "user_banned":
|
||||||
|
return `<:banned:1042831836675588146> ${await getUsername(
|
||||||
|
message.id
|
||||||
|
)} was banned`;
|
||||||
|
case "channel_renamed":
|
||||||
|
return `<:channel_renamed:1042831837912891392> ${await getUsername(
|
||||||
|
message.by
|
||||||
|
)} renamed the channel to **${message.name}**`;
|
||||||
|
case "channel_icon_changed":
|
||||||
|
return `<:channel_icon:1042831840538542222> ${await getUsername(
|
||||||
|
message.by
|
||||||
|
)} changed the channel icon`;
|
||||||
|
case "channel_description_changed":
|
||||||
|
return `<:channel_description:1042831839217328228> ${await getUsername(
|
||||||
|
message.by
|
||||||
|
)} changed the channel description`;
|
||||||
|
case "text":
|
||||||
|
return message.content;
|
||||||
|
default:
|
||||||
|
return Object.entries(message)
|
||||||
|
.map((e) => `${e[0]}: ${e[1]}`)
|
||||||
|
.join(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,4 +10,9 @@ export const CONFIG_KEYS = {
|
||||||
"If enabled, all messages by users who opted out of their messages being bridged (`/bridge opt_out`) will be deleted. " +
|
"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.",
|
"You should enable this if your Revolt server is bridged to a mostly unmoderated Discord server.",
|
||||||
},
|
},
|
||||||
|
disable_system_messages: {
|
||||||
|
friendlyName: "Don't bridge system messages",
|
||||||
|
description:
|
||||||
|
"If enabled, system messages (e.g. join/leave events) won't be bridged.",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue