mirror of
https://github.com/ZeppelinBot/Zeppelin.git
synced 2025-05-10 20:35:02 +00:00
Finish preliminary rework, ready to test
This commit is contained in:
parent
57893e7f76
commit
d0a1beb809
177 changed files with 854 additions and 707 deletions
|
@ -20,6 +20,7 @@ import { mapToPublicFn } from "../../pluginUtils";
|
|||
import { EventEmitter } from "events";
|
||||
import { onMutesEvent } from "./functions/onMutesEvent";
|
||||
import { offMutesEvent } from "./functions/offMutesEvent";
|
||||
import { GuildMember } from "discord.js";
|
||||
|
||||
const defaultOptions = {
|
||||
config: {
|
||||
|
@ -92,9 +93,9 @@ export const MutesPlugin = zeppelinGuildPlugin<MutesPluginType>()({
|
|||
muteUser: mapToPublicFn(muteUser),
|
||||
unmuteUser: mapToPublicFn(unmuteUser),
|
||||
hasMutedRole(pluginData) {
|
||||
return (member: Member) => {
|
||||
return (member: GuildMember) => {
|
||||
const muteRole = pluginData.config.get().mute_role;
|
||||
return muteRole ? member.roles.includes(muteRole) : false;
|
||||
return muteRole ? member.roles.cache.has(muteRole) : false;
|
||||
};
|
||||
},
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { mutesCmd } from "../types";
|
||||
|
||||
import { sendSuccessMessage } from "../../../pluginUtils";
|
||||
import { User } from "discord.js";
|
||||
|
||||
export const ClearBannedMutesCmd = mutesCmd({
|
||||
trigger: "clear_banned_mutes",
|
||||
|
@ -8,17 +9,14 @@ export const ClearBannedMutesCmd = mutesCmd({
|
|||
description: "Clear dangling mutes for members who have been banned",
|
||||
|
||||
async run({ pluginData, message: msg }) {
|
||||
await msg.channel.createMessage("Clearing mutes from banned users...");
|
||||
await msg.channel.send("Clearing mutes from banned users...");
|
||||
|
||||
const activeMutes = await pluginData.state.mutes.getActiveMutes();
|
||||
|
||||
// Mismatch in Eris docs and actual result here, based on Eris's code comments anyway
|
||||
const bans: Array<{ reason: string; user: User }> = (await pluginData.guild.getBans()) as any;
|
||||
const bans: Array<{ reason: string; user: User }> = (await pluginData.guild.bans.fetch({ cache: true })) as any;
|
||||
const bannedIds = bans.map(b => b.user.id);
|
||||
|
||||
await msg.channel.createMessage(
|
||||
`Found ${activeMutes.length} mutes and ${bannedIds.length} bans, cross-referencing...`,
|
||||
);
|
||||
await msg.channel.send(`Found ${activeMutes.length} mutes and ${bannedIds.length} bans, cross-referencing...`);
|
||||
|
||||
let cleared = 0;
|
||||
for (const mute of activeMutes) {
|
||||
|
|
|
@ -12,14 +12,14 @@ export const ClearMutesWithoutRoleCmd = mutesCmd({
|
|||
const muteRole = pluginData.config.get().mute_role;
|
||||
if (!muteRole) return;
|
||||
|
||||
await msg.channel.createMessage("Clearing mutes from members that don't have the mute role...");
|
||||
await msg.channel.send("Clearing mutes from members that don't have the mute role...");
|
||||
|
||||
let cleared = 0;
|
||||
for (const mute of activeMutes) {
|
||||
const member = await resolveMember(pluginData.client, pluginData.guild, mute.user_id);
|
||||
if (!member) continue;
|
||||
|
||||
if (!member.roles.includes(muteRole)) {
|
||||
if (!member.roles.cache.has(muteRole)) {
|
||||
await pluginData.state.mutes.clear(mute.user_id);
|
||||
cleared++;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import { DBDateFormat, isFullMessage, MINUTES, noop, resolveMember } from "../..
|
|||
import moment from "moment-timezone";
|
||||
import { humanizeDurationShort } from "../../../humanizeDurationShort";
|
||||
import { getBaseUrl } from "../../../pluginUtils";
|
||||
import { GuildMember } from "discord.js";
|
||||
|
||||
export const MutesCmd = mutesCmd({
|
||||
trigger: "mutes",
|
||||
|
@ -21,7 +22,7 @@ export const MutesCmd = mutesCmd({
|
|||
},
|
||||
|
||||
async run({ pluginData, message: msg, args }) {
|
||||
const listMessagePromise = msg.channel.createMessage("Loading mutes...");
|
||||
const listMessagePromise = msg.channel.send("Loading mutes...");
|
||||
const mutesPerPage = 10;
|
||||
let totalMutes = 0;
|
||||
let hasFilters = false;
|
||||
|
@ -47,13 +48,13 @@ export const MutesCmd = mutesCmd({
|
|||
if (args.manual) {
|
||||
// Show only manual mutes (i.e. "Muted" role added without a logged mute)
|
||||
const muteUserIds = new Set(activeMutes.map(m => m.user_id));
|
||||
const manuallyMutedMembers: Member[] = [];
|
||||
const manuallyMutedMembers: GuildMember[] = [];
|
||||
const muteRole = pluginData.config.get().mute_role;
|
||||
|
||||
if (muteRole) {
|
||||
pluginData.guild.members.forEach(member => {
|
||||
pluginData.guild.members.cache.forEach(member => {
|
||||
if (muteUserIds.has(member.id)) return;
|
||||
if (member.roles.includes(muteRole)) manuallyMutedMembers.push(member);
|
||||
if (member.roles.cache.has(muteRole)) manuallyMutedMembers.push(member);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -85,7 +86,7 @@ export const MutesCmd = mutesCmd({
|
|||
|
||||
if (!member) {
|
||||
if (!bannedIds) {
|
||||
const bans = await pluginData.guild.getBans();
|
||||
const bans = await pluginData.guild.bans.fetch({ cache: true });
|
||||
bannedIds = bans.map(u => u.user.id);
|
||||
}
|
||||
|
||||
|
@ -111,7 +112,7 @@ export const MutesCmd = mutesCmd({
|
|||
const muteCasesById = muteCases.reduce((map, c) => map.set(c.id, c), new Map());
|
||||
|
||||
lines = filteredMutes.map(mute => {
|
||||
const user = pluginData.client.user!.get(mute.user_id);
|
||||
const user = pluginData.client.users.resolve(mute.user_id);
|
||||
const username = user ? `${user.username}#${user.discriminator}` : "Unknown#0000";
|
||||
const theCase = muteCasesById.get(mute.case_id);
|
||||
const caseName = theCase ? `Case #${theCase.case_number}` : "No case";
|
||||
|
@ -194,29 +195,31 @@ export const MutesCmd = mutesCmd({
|
|||
|
||||
if (totalPages > 1) {
|
||||
hasReactions = true;
|
||||
listMessage.addReaction("⬅");
|
||||
listMessage.addReaction("➡");
|
||||
listMessage.react("⬅");
|
||||
listMessage.react("➡");
|
||||
|
||||
const paginationReactionListener = pluginData.events.on(
|
||||
"messageReactionAdd",
|
||||
({ args: { message: rMsg, emoji, member } }) => {
|
||||
async ({ args: { reaction, user } }) => {
|
||||
const rMsg = reaction.message;
|
||||
const member = await pluginData.guild.members.fetch(user.id);
|
||||
if (!isFullMessage(rMsg)) return;
|
||||
if (rMsg.id !== listMessage.id) return;
|
||||
if (member.id !== msg.author.id) return;
|
||||
if (!["⬅", "➡"].includes(emoji.name)) return;
|
||||
if (!["⬅", "➡"].includes(reaction.emoji.name!)) return;
|
||||
|
||||
if (emoji.name === "⬅" && currentPage > 1) {
|
||||
if (reaction.emoji.name === "⬅" && currentPage > 1) {
|
||||
drawListPage(currentPage - 1);
|
||||
} else if (emoji.name === "➡" && currentPage < totalPages) {
|
||||
} else if (reaction.emoji.name === "➡" && currentPage < totalPages) {
|
||||
drawListPage(currentPage + 1);
|
||||
}
|
||||
|
||||
rMsg.removeReaction(emoji.name, member.id).catch(noop);
|
||||
reaction.remove().catch(noop);
|
||||
},
|
||||
);
|
||||
|
||||
clearReactionsFn = () => {
|
||||
listMessage.removeReactions().catch(noop);
|
||||
listMessage.reactions.removeAll().catch(noop);
|
||||
pluginData.events.off("messageReactionAdd", paginationReactionListener);
|
||||
};
|
||||
bumpClearReactionsTimeout();
|
||||
|
|
|
@ -5,10 +5,10 @@ import { mutesEvt } from "../types";
|
|||
*/
|
||||
export const ClearActiveMuteOnMemberBanEvt = mutesEvt({
|
||||
event: "guildBanAdd",
|
||||
async listener({ pluginData, args: { user } }) {
|
||||
const mute = await pluginData.state.mutes.findExistingMuteForUserId(user.id);
|
||||
async listener({ pluginData, args: { ban } }) {
|
||||
const mute = await pluginData.state.mutes.findExistingMuteForUserId(ban.user.id);
|
||||
if (mute) {
|
||||
pluginData.state.mutes.clear(user.id);
|
||||
pluginData.state.mutes.clear(ban.user.id);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@ import { memberHasMutedRole } from "../functions/memberHasMutedRole";
|
|||
*/
|
||||
export const ClearActiveMuteOnRoleRemovalEvt = mutesEvt({
|
||||
event: "guildMemberUpdate",
|
||||
async listener({ pluginData, args: { member } }) {
|
||||
async listener({ pluginData, args: { oldMember, newMember: member } }) {
|
||||
const muteRole = pluginData.config.get().mute_role;
|
||||
if (!muteRole) return;
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ export const ReapplyActiveMuteOnJoinEvt = mutesEvt({
|
|||
|
||||
if (muteRole) {
|
||||
const memberRoleLock = await pluginData.locks.acquire(memberRolesLock(member));
|
||||
await member.addRole(muteRole);
|
||||
await member.roles.add(muteRole);
|
||||
memberRoleLock.unlock();
|
||||
}
|
||||
|
||||
|
|
|
@ -16,17 +16,17 @@ export async function clearExpiredMutes(pluginData: GuildPluginData<MutesPluginT
|
|||
|
||||
const muteRole = pluginData.config.get().mute_role;
|
||||
if (muteRole) {
|
||||
await member.removeRole(muteRole);
|
||||
member.roles = member.roles.filter(r => r !== muteRole);
|
||||
await member.roles.remove(muteRole);
|
||||
}
|
||||
if (mute.roles_to_restore) {
|
||||
const memberOptions: MemberOptions = {};
|
||||
const guildRoles = pluginData.guild.roles;
|
||||
memberOptions.roles = Array.from(
|
||||
new Set([...mute.roles_to_restore, ...member.roles.filter(x => x !== muteRole && guildRoles.has(x))]),
|
||||
);
|
||||
await member.edit(memberOptions);
|
||||
member.roles = memberOptions.roles;
|
||||
const guildRoles = pluginData.guild.roles.cache;
|
||||
let newRoles: string[] = member.roles.cache.keyArray();
|
||||
newRoles =
|
||||
muteRole && newRoles.includes(muteRole) ? newRoles.splice(newRoles.indexOf(muteRole), 1) : newRoles;
|
||||
for (const toRestore of mute.roles_to_restore) {
|
||||
if (guildRoles.has(toRestore) && toRestore !== muteRole) newRoles.push(toRestore);
|
||||
}
|
||||
await member.roles.set(newRoles);
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { GuildMember } from "discord.js";
|
||||
import { GuildPluginData } from "knub";
|
||||
import { MutesPluginType } from "../types";
|
||||
|
||||
export function memberHasMutedRole(pluginData: GuildPluginData<MutesPluginType>, member: Member): boolean {
|
||||
export function memberHasMutedRole(pluginData: GuildPluginData<MutesPluginType>, member: GuildMember): boolean {
|
||||
const muteRole = pluginData.config.get().mute_role;
|
||||
return muteRole ? member.roles.includes(muteRole) : false;
|
||||
return muteRole ? member.roles.cache.has(muteRole) : false;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import { LogType } from "../../../data/LogType";
|
|||
import { Case } from "../../../data/entities/Case";
|
||||
import { LogsPlugin } from "../../../plugins/Logs/LogsPlugin";
|
||||
import { muteLock } from "../../../utils/lockNameHelpers";
|
||||
import { TextChannel, User } from "discord.js";
|
||||
|
||||
export async function muteUser(
|
||||
pluginData: GuildPluginData<MutesPluginType>,
|
||||
|
@ -58,8 +59,8 @@ export async function muteUser(
|
|||
if (member) {
|
||||
const logs = pluginData.getPlugin(LogsPlugin);
|
||||
// remove and store any roles to be removed/restored
|
||||
const currentUserRoles = member.roles;
|
||||
const memberOptions: MemberOptions = {};
|
||||
const currentUserRoles = member.roles.cache.keyArray();
|
||||
let newRoles: string[] = currentUserRoles;
|
||||
const removeRoles = removeRolesOnMuteOverride ?? config.remove_roles_on_mute;
|
||||
const restoreRoles = restoreRolesOnMuteOverride ?? config.restore_roles_on_mute;
|
||||
|
||||
|
@ -67,13 +68,13 @@ export async function muteUser(
|
|||
if (!Array.isArray(removeRoles)) {
|
||||
if (removeRoles) {
|
||||
// exclude managed roles from being removed
|
||||
const managedRoles = pluginData.guild.roles.filter(x => x.managed).map(y => y.id);
|
||||
memberOptions.roles = managedRoles.filter(x => member.roles.includes(x));
|
||||
await member.edit(memberOptions);
|
||||
const managedRoles = pluginData.guild.roles.cache.filter(x => x.managed).map(y => y.id);
|
||||
newRoles = currentUserRoles.filter(r => !managedRoles.includes(r));
|
||||
await member.roles.set(newRoles);
|
||||
}
|
||||
} else {
|
||||
memberOptions.roles = currentUserRoles.filter(x => !(<string[]>removeRoles).includes(x));
|
||||
await member.edit(memberOptions);
|
||||
newRoles = currentUserRoles.filter(x => !(<string[]>removeRoles).includes(x));
|
||||
await member.roles.set(newRoles);
|
||||
}
|
||||
|
||||
// set roles to be restored
|
||||
|
@ -86,11 +87,11 @@ export async function muteUser(
|
|||
}
|
||||
|
||||
// Apply mute role if it's missing
|
||||
if (!member.roles.includes(muteRole)) {
|
||||
if (!currentUserRoles.includes(muteRole)) {
|
||||
try {
|
||||
await member.addRole(muteRole);
|
||||
await member.roles.add(muteRole);
|
||||
} catch (e) {
|
||||
const actualMuteRole = pluginData.guild.roles.find(x => x.id === muteRole);
|
||||
const actualMuteRole = pluginData.guild.roles.cache.find(x => x.id === muteRole);
|
||||
if (!actualMuteRole) {
|
||||
lock.unlock();
|
||||
logs.log(LogType.BOT_ALERT, {
|
||||
|
@ -100,9 +101,9 @@ export async function muteUser(
|
|||
}
|
||||
|
||||
const zep = await resolveMember(pluginData.client, pluginData.guild, pluginData.client.user!.id);
|
||||
const zepRoles = pluginData.guild.roles.filter(x => zep!.roles.includes(x.id));
|
||||
const zepRoles = pluginData.guild.roles.cache.filter(x => zep!.roles.cache.has(x.id));
|
||||
// If we have roles and one of them is above the muted role, throw generic error
|
||||
if (zepRoles.length >= 0 && zepRoles.some(zepRole => zepRole.position > actualMuteRole.position)) {
|
||||
if (zepRoles.size >= 0 && zepRoles.some(zepRole => zepRole.position > actualMuteRole.position)) {
|
||||
lock.unlock();
|
||||
logs.log(LogType.BOT_ALERT, {
|
||||
body: `Cannot mute user ${member.id}: ${e}`,
|
||||
|
@ -125,7 +126,7 @@ export async function muteUser(
|
|||
if (moveToVoiceChannel || cfg.kick_from_voice_channel) {
|
||||
// TODO: Add back the voiceState check once we figure out how to get voice state for guild members that are loaded on-demand
|
||||
try {
|
||||
await member.edit({ channelID: moveToVoiceChannel });
|
||||
await member.edit({ channel: moveToVoiceChannel });
|
||||
} catch {} // tslint:disable-line
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,18 +36,17 @@ export async function unmuteUser(
|
|||
const lock = await pluginData.locks.acquire(memberRolesLock(member));
|
||||
|
||||
const muteRole = pluginData.config.get().mute_role;
|
||||
if (muteRole && member.roles.includes(muteRole)) {
|
||||
await member.removeRole(muteRole);
|
||||
member.roles = member.roles.filter(r => r !== muteRole);
|
||||
if (muteRole && member.roles.cache.has(muteRole)) {
|
||||
await member.roles.remove(muteRole);
|
||||
}
|
||||
if (existingMute?.roles_to_restore) {
|
||||
const memberOptions: MemberOptions = {};
|
||||
const guildRoles = pluginData.guild.roles;
|
||||
memberOptions.roles = Array.from(
|
||||
new Set([...existingMute.roles_to_restore, ...member.roles.filter(x => x !== muteRole && guildRoles.has(x))]),
|
||||
);
|
||||
await member.edit(memberOptions);
|
||||
member.roles = memberOptions.roles;
|
||||
const guildRoles = pluginData.guild.roles.cache;
|
||||
let newRoles: string[] = member.roles.cache.keyArray();
|
||||
newRoles = muteRole && newRoles.includes(muteRole) ? newRoles.splice(newRoles.indexOf(muteRole), 1) : newRoles;
|
||||
for (const toRestore of existingMute.roles_to_restore) {
|
||||
if (guildRoles.has(toRestore) && toRestore !== muteRole) newRoles.push(toRestore);
|
||||
}
|
||||
await member.roles.set(newRoles);
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
|
@ -85,7 +84,7 @@ export async function unmuteUser(
|
|||
});
|
||||
|
||||
// Log the action
|
||||
const mod = pluginData.client.user!.get(modId);
|
||||
const mod = pluginData.client.users.fetch(modId);
|
||||
if (unmuteTime) {
|
||||
pluginData.state.serverLogs.log(LogType.MEMBER_TIMED_UNMUTE, {
|
||||
mod: stripObjectToScalars(mod),
|
||||
|
|
|
@ -11,6 +11,7 @@ import { GuildMutes } from "../../data/GuildMutes";
|
|||
import { CaseArgs } from "../Cases/types";
|
||||
import Timeout = NodeJS.Timeout;
|
||||
import { EventEmitter } from "events";
|
||||
import { GuildMember } from "discord.js";
|
||||
|
||||
export const ConfigSchema = t.type({
|
||||
mute_role: tNullable(t.string),
|
||||
|
@ -58,7 +59,7 @@ export interface MutesPluginType extends BasePluginType {
|
|||
}
|
||||
|
||||
export interface IMuteWithDetails extends Mute {
|
||||
member?: Member;
|
||||
member?: GuildMember;
|
||||
banned?: boolean;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue