Finish preliminary rework, ready to test
This commit is contained in:
parent
57893e7f76
commit
d0a1beb809
177 changed files with 854 additions and 707 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -77,3 +77,5 @@ npm-audit.txt
|
||||||
# Debug files
|
# Debug files
|
||||||
*.debug.ts
|
*.debug.ts
|
||||||
*.debug.js
|
*.debug.js
|
||||||
|
|
||||||
|
.vscode/
|
||||||
|
|
|
@ -211,7 +211,8 @@ export class GuildSavedMessages extends BaseGuildRepository {
|
||||||
|
|
||||||
const newMessage = { ...oldMessage, data: newData };
|
const newMessage = { ...oldMessage, data: newData };
|
||||||
|
|
||||||
await this.messages.update(
|
//@ts-ignore
|
||||||
|
await this.messages.update( // FIXME?
|
||||||
{ id },
|
{ id },
|
||||||
{
|
{
|
||||||
data: newData,
|
data: newData,
|
||||||
|
|
|
@ -53,13 +53,13 @@ export const AddRolesAction = automodAction({
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
members.map(async member => {
|
members.map(async member => {
|
||||||
const memberRoles = new Set(member.roles);
|
const memberRoles = new Set(member.roles.cache.keyArray());
|
||||||
for (const roleId of rolesToAssign) {
|
for (const roleId of rolesToAssign) {
|
||||||
memberRoles.add(roleId);
|
memberRoles.add(roleId);
|
||||||
ignoreRoleChange(pluginData, member.id, roleId);
|
ignoreRoleChange(pluginData, member.id, roleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memberRoles.size === member.roles.length) {
|
if (memberRoles.size === member.roles.cache.size) {
|
||||||
// No role changes
|
// No role changes
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,6 @@ export const AddRolesAction = automodAction({
|
||||||
await member.edit({
|
await member.edit({
|
||||||
roles: rolesArr,
|
roles: rolesArr,
|
||||||
});
|
});
|
||||||
member.roles = rolesArr; // Make sure we know of the new roles internally as well
|
|
||||||
|
|
||||||
memberRoleLock.unlock();
|
memberRoleLock.unlock();
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -57,13 +57,13 @@ export const RemoveRolesAction = automodAction({
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
members.map(async member => {
|
members.map(async member => {
|
||||||
const memberRoles = new Set(member.roles);
|
const memberRoles = new Set(member.roles.cache.keyArray());
|
||||||
for (const roleId of rolesToRemove) {
|
for (const roleId of rolesToRemove) {
|
||||||
memberRoles.delete(roleId);
|
memberRoles.delete(roleId);
|
||||||
ignoreRoleChange(pluginData, member.id, roleId);
|
ignoreRoleChange(pluginData, member.id, roleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memberRoles.size === member.roles.length) {
|
if (memberRoles.size === member.roles.cache.size) {
|
||||||
// No role changes
|
// No role changes
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,6 @@ export const RemoveRolesAction = automodAction({
|
||||||
await member.edit({
|
await member.edit({
|
||||||
roles: rolesArr,
|
roles: rolesArr,
|
||||||
});
|
});
|
||||||
member.roles = rolesArr; // Make sure we know of the new roles internally as well
|
|
||||||
|
|
||||||
memberRoleLock.unlock();
|
memberRoleLock.unlock();
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -23,11 +23,11 @@ export function getTextMatchPartialSummary(
|
||||||
} else if (type === "username") {
|
} else if (type === "username") {
|
||||||
return `username: ${context.user!.username}`;
|
return `username: ${context.user!.username}`;
|
||||||
} else if (type === "nickname") {
|
} else if (type === "nickname") {
|
||||||
return `nickname: ${context.member!.nick}`;
|
return `nickname: ${context.member!.nickname}`;
|
||||||
} else if (type === "visiblename") {
|
} else if (type === "visiblename") {
|
||||||
const visibleName = context.member?.nick || context.user!.username;
|
const visibleName = context.member?.nickname || context.user!.username;
|
||||||
return `visible name: ${visibleName}`;
|
return `visible name: ${visibleName}`;
|
||||||
} else if (type === "customstatus") {
|
} else if (type === "customstatus") {
|
||||||
return `custom status: ${context.member!.game!.state}`;
|
return `custom status: ${context.member!.presence.activities.find(a => a.type === "CUSTOM_STATUS")?.name}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ export const MemberJoinTrigger = automodTrigger<unknown>()({
|
||||||
|
|
||||||
if (triggerConfig.only_new) {
|
if (triggerConfig.only_new) {
|
||||||
const threshold = Date.now() - convertDelayStringToMS(triggerConfig.new_threshold)!;
|
const threshold = Date.now() - convertDelayStringToMS(triggerConfig.new_threshold)!;
|
||||||
return context.member.createdAt >= threshold ? {} : null;
|
return context.member.user.createdTimestamp >= threshold ? {} : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { botControlCmd } from "../types";
|
||||||
import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { ApiPermissions } from "@shared/apiPermissions";
|
import { ApiPermissions } from "@shared/apiPermissions";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export const AddDashboardUserCmd = botControlCmd({
|
export const AddDashboardUserCmd = botControlCmd({
|
||||||
trigger: ["add_dashboard_user"],
|
trigger: ["add_dashboard_user"],
|
||||||
|
@ -18,7 +19,7 @@ export const AddDashboardUserCmd = botControlCmd({
|
||||||
async run({ pluginData, message: msg, args }) {
|
async run({ pluginData, message: msg, args }) {
|
||||||
const guild = await pluginData.state.allowedGuilds.find(args.guildId);
|
const guild = await pluginData.state.allowedGuilds.find(args.guildId);
|
||||||
if (!guild) {
|
if (!guild) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Server is not using Zeppelin");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "Server is not using Zeppelin");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +40,7 @@ export const AddDashboardUserCmd = botControlCmd({
|
||||||
);
|
);
|
||||||
sendSuccessMessage(
|
sendSuccessMessage(
|
||||||
pluginData,
|
pluginData,
|
||||||
msg.channel,
|
msg.channel as TextChannel,
|
||||||
`The following users were given dashboard access for **${guild.name}**:\n\n${userNameList}`,
|
`The following users were given dashboard access for **${guild.name}**:\n\n${userNameList}`,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../..
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { isSnowflake } from "../../../utils";
|
import { isSnowflake } from "../../../utils";
|
||||||
import { ApiPermissions } from "@shared/apiPermissions";
|
import { ApiPermissions } from "@shared/apiPermissions";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export const AllowServerCmd = botControlCmd({
|
export const AllowServerCmd = botControlCmd({
|
||||||
trigger: ["allow_server", "allowserver", "add_server", "addserver"],
|
trigger: ["allow_server", "allowserver", "add_server", "addserver"],
|
||||||
|
@ -19,17 +20,17 @@ export const AllowServerCmd = botControlCmd({
|
||||||
async run({ pluginData, message: msg, args }) {
|
async run({ pluginData, message: msg, args }) {
|
||||||
const existing = await pluginData.state.allowedGuilds.find(args.guildId);
|
const existing = await pluginData.state.allowedGuilds.find(args.guildId);
|
||||||
if (existing) {
|
if (existing) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Server is already allowed!");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "Server is already allowed!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isSnowflake(args.guildId)) {
|
if (!isSnowflake(args.guildId)) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Invalid server ID!");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "Invalid server ID!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.userId && !isSnowflake(args.userId)) {
|
if (args.userId && !isSnowflake(args.userId)) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Invalid user ID!");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "Invalid user ID!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +41,6 @@ export const AllowServerCmd = botControlCmd({
|
||||||
await pluginData.state.apiPermissionAssignments.addUser(args.guildId, args.userId, [ApiPermissions.EditConfig]);
|
await pluginData.state.apiPermissionAssignments.addUser(args.guildId, args.userId, [ApiPermissions.EditConfig]);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendSuccessMessage(pluginData, msg.channel, "Server is now allowed to use Zeppelin!");
|
sendSuccessMessage(pluginData, msg.channel as TextChannel, "Server is now allowed to use Zeppelin!");
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { botControlCmd } from "../types";
|
||||||
import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { noop } from "../../../utils";
|
import { noop } from "../../../utils";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export const DisallowServerCmd = botControlCmd({
|
export const DisallowServerCmd = botControlCmd({
|
||||||
trigger: ["disallow_server", "disallowserver", "remove_server", "removeserver"],
|
trigger: ["disallow_server", "disallowserver", "remove_server", "removeserver"],
|
||||||
|
@ -17,12 +18,15 @@ export const DisallowServerCmd = botControlCmd({
|
||||||
async run({ pluginData, message: msg, args }) {
|
async run({ pluginData, message: msg, args }) {
|
||||||
const existing = await pluginData.state.allowedGuilds.find(args.guildId);
|
const existing = await pluginData.state.allowedGuilds.find(args.guildId);
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "That server is not allowed in the first place!");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "That server is not allowed in the first place!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await pluginData.state.allowedGuilds.remove(args.guildId);
|
await pluginData.state.allowedGuilds.remove(args.guildId);
|
||||||
await pluginData.client.leaveGuild(args.guildId).catch(noop);
|
await pluginData.client.guilds.cache
|
||||||
sendSuccessMessage(pluginData, msg.channel, "Server removed!");
|
.get(args.guildId)
|
||||||
|
?.leave()
|
||||||
|
.catch(noop);
|
||||||
|
sendSuccessMessage(pluginData, msg.channel as TextChannel, "Server removed!");
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { botControlCmd } from "../types";
|
||||||
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { resolveInvite, verboseUserMention } from "../../../utils";
|
import { resolveInvite, verboseUserMention } from "../../../utils";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
const REQUIRED_MEMBER_COUNT = 5000;
|
const REQUIRED_MEMBER_COUNT = 5000;
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ export const EligibleCmd = botControlCmd({
|
||||||
if ((await pluginData.state.apiPermissionAssignments.getByUserId(args.user.id)).length) {
|
if ((await pluginData.state.apiPermissionAssignments.getByUserId(args.user.id)).length) {
|
||||||
sendSuccessMessage(
|
sendSuccessMessage(
|
||||||
pluginData,
|
pluginData,
|
||||||
msg.channel,
|
msg.channel as TextChannel,
|
||||||
`${verboseUserMention(args.user)} is an existing bot operator. They are eligible!`,
|
`${verboseUserMention(args.user)} is an existing bot operator. They are eligible!`,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
@ -26,17 +27,17 @@ export const EligibleCmd = botControlCmd({
|
||||||
|
|
||||||
const invite = await resolveInvite(pluginData.client, args.inviteCode, true);
|
const invite = await resolveInvite(pluginData.client, args.inviteCode, true);
|
||||||
if (!invite || !invite.guild) {
|
if (!invite || !invite.guild) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Could not resolve server from invite");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "Could not resolve server from invite");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invite.guild.features.includes("PARTNERED")) {
|
if (invite.guild.features.includes("PARTNERED")) {
|
||||||
sendSuccessMessage(pluginData, msg.channel, `Server is partnered. It is eligible!`);
|
sendSuccessMessage(pluginData, msg.channel as TextChannel, `Server is partnered. It is eligible!`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invite.guild.features.includes("VERIFIED")) {
|
if (invite.guild.features.includes("VERIFIED")) {
|
||||||
sendSuccessMessage(pluginData, msg.channel, `Server is verified. It is eligible!`);
|
sendSuccessMessage(pluginData, msg.channel as TextChannel, `Server is verified. It is eligible!`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ export const EligibleCmd = botControlCmd({
|
||||||
if (memberCount >= REQUIRED_MEMBER_COUNT) {
|
if (memberCount >= REQUIRED_MEMBER_COUNT) {
|
||||||
sendSuccessMessage(
|
sendSuccessMessage(
|
||||||
pluginData,
|
pluginData,
|
||||||
msg.channel,
|
msg.channel as TextChannel,
|
||||||
`Server has ${memberCount} members, which is equal or higher than the required ${REQUIRED_MEMBER_COUNT}. It is eligible!`,
|
`Server has ${memberCount} members, which is equal or higher than the required ${REQUIRED_MEMBER_COUNT}. It is eligible!`,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
@ -52,7 +53,7 @@ export const EligibleCmd = botControlCmd({
|
||||||
|
|
||||||
sendErrorMessage(
|
sendErrorMessage(
|
||||||
pluginData,
|
pluginData,
|
||||||
msg.channel,
|
msg.channel as TextChannel,
|
||||||
`Server **${invite.guild.name}** (\`${invite.guild.id}\`) is not eligible`,
|
`Server **${invite.guild.name}** (\`${invite.guild.id}\`) is not eligible`,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { botControlCmd } from "../types";
|
import { botControlCmd } from "../types";
|
||||||
import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export const LeaveServerCmd = botControlCmd({
|
export const LeaveServerCmd = botControlCmd({
|
||||||
trigger: ["leave_server", "leave_guild"],
|
trigger: ["leave_server", "leave_guild"],
|
||||||
|
@ -14,21 +15,21 @@ export const LeaveServerCmd = botControlCmd({
|
||||||
},
|
},
|
||||||
|
|
||||||
async run({ pluginData, message: msg, args }) {
|
async run({ pluginData, message: msg, args }) {
|
||||||
if (!pluginData.client.guilds.has(args.guildId)) {
|
if (!pluginData.client.guilds.cache.has(args.guildId)) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "I am not in that guild");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "I am not in that guild");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const guildToLeave = pluginData.client.guilds.get(args.guildId)!;
|
const guildToLeave = await pluginData.client.guilds.fetch(args.guildId)!;
|
||||||
const guildName = guildToLeave.name;
|
const guildName = guildToLeave.name;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await pluginData.client.leaveGuild(args.guildId);
|
await pluginData.client.guilds.cache.get(args.guildId)?.leave();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
sendErrorMessage(pluginData, msg.channel, `Failed to leave guild: ${e.message}`);
|
sendErrorMessage(pluginData, msg.channel as TextChannel, `Failed to leave guild: ${e.message}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendSuccessMessage(pluginData, msg.channel, `Left guild **${guildName}**`);
|
sendSuccessMessage(pluginData, msg.channel as TextChannel, `Left guild **${guildName}**`);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { createChunkedMessage, resolveUser } from "../../../utils";
|
import { createChunkedMessage, resolveUser } from "../../../utils";
|
||||||
import { AllowedGuild } from "../../../data/entities/AllowedGuild";
|
import { AllowedGuild } from "../../../data/entities/AllowedGuild";
|
||||||
import { ApiPermissionAssignment } from "../../../data/entities/ApiPermissionAssignment";
|
import { ApiPermissionAssignment } from "../../../data/entities/ApiPermissionAssignment";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export const ListDashboardPermsCmd = botControlCmd({
|
export const ListDashboardPermsCmd = botControlCmd({
|
||||||
trigger: ["list_dashboard_permissions", "list_dashboard_perms", "list_dash_permissionss", "list_dash_perms"],
|
trigger: ["list_dashboard_permissions", "list_dashboard_perms", "list_dash_permissionss", "list_dash_perms"],
|
||||||
|
@ -19,7 +20,7 @@ export const ListDashboardPermsCmd = botControlCmd({
|
||||||
|
|
||||||
async run({ pluginData, message: msg, args }) {
|
async run({ pluginData, message: msg, args }) {
|
||||||
if (!args.user && !args.guildId) {
|
if (!args.user && !args.guildId) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Must specify at least guildId, user, or both.");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "Must specify at least guildId, user, or both.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +28,7 @@ export const ListDashboardPermsCmd = botControlCmd({
|
||||||
if (args.guildId) {
|
if (args.guildId) {
|
||||||
guild = await pluginData.state.allowedGuilds.find(args.guildId);
|
guild = await pluginData.state.allowedGuilds.find(args.guildId);
|
||||||
if (!guild) {
|
if (!guild) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Server is not using Zeppelin");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "Server is not using Zeppelin");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +37,7 @@ export const ListDashboardPermsCmd = botControlCmd({
|
||||||
if (args.user) {
|
if (args.user) {
|
||||||
existingUserAssignment = await pluginData.state.apiPermissionAssignments.getByUserId(args.user.id);
|
existingUserAssignment = await pluginData.state.apiPermissionAssignments.getByUserId(args.user.id);
|
||||||
if (existingUserAssignment.length === 0) {
|
if (existingUserAssignment.length === 0) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "The user has no assigned permissions.");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "The user has no assigned permissions.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +60,7 @@ export const ListDashboardPermsCmd = botControlCmd({
|
||||||
if (finalMessage === "") {
|
if (finalMessage === "") {
|
||||||
sendErrorMessage(
|
sendErrorMessage(
|
||||||
pluginData,
|
pluginData,
|
||||||
msg.channel,
|
msg.channel as TextChannel,
|
||||||
`The user ${userInfo} has no assigned permissions on the specified server.`,
|
`The user ${userInfo} has no assigned permissions on the specified server.`,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
@ -70,7 +71,11 @@ export const ListDashboardPermsCmd = botControlCmd({
|
||||||
|
|
||||||
const existingGuildAssignment = await pluginData.state.apiPermissionAssignments.getByGuildId(guild.id);
|
const existingGuildAssignment = await pluginData.state.apiPermissionAssignments.getByGuildId(guild.id);
|
||||||
if (existingGuildAssignment.length === 0) {
|
if (existingGuildAssignment.length === 0) {
|
||||||
sendErrorMessage(pluginData, msg.channel, `The server ${guildInfo} has no assigned permissions.`);
|
sendErrorMessage(
|
||||||
|
pluginData,
|
||||||
|
msg.channel as TextChannel,
|
||||||
|
`The server ${guildInfo} has no assigned permissions.`,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +88,6 @@ export const ListDashboardPermsCmd = botControlCmd({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await sendSuccessMessage(pluginData, msg.channel, finalMessage.trim(), {});
|
await sendSuccessMessage(pluginData, msg.channel as TextChannel, finalMessage.trim(), {});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../..
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { ApiPermissions } from "@shared/apiPermissions";
|
import { ApiPermissions } from "@shared/apiPermissions";
|
||||||
import { resolveUser, UnknownUser } from "../../../utils";
|
import { resolveUser, UnknownUser } from "../../../utils";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export const ListDashboardUsersCmd = botControlCmd({
|
export const ListDashboardUsersCmd = botControlCmd({
|
||||||
trigger: ["list_dashboard_users"],
|
trigger: ["list_dashboard_users"],
|
||||||
|
@ -18,7 +19,7 @@ export const ListDashboardUsersCmd = botControlCmd({
|
||||||
async run({ pluginData, message: msg, args }) {
|
async run({ pluginData, message: msg, args }) {
|
||||||
const guild = await pluginData.state.allowedGuilds.find(args.guildId);
|
const guild = await pluginData.state.allowedGuilds.find(args.guildId);
|
||||||
if (!guild) {
|
if (!guild) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Server is not using Zeppelin");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "Server is not using Zeppelin");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ export const ListDashboardUsersCmd = botControlCmd({
|
||||||
|
|
||||||
sendSuccessMessage(
|
sendSuccessMessage(
|
||||||
pluginData,
|
pluginData,
|
||||||
msg.channel,
|
msg.channel as TextChannel,
|
||||||
`The following users have dashboard access for **${guild.name}**:\n\n${userNameList}`,
|
`The following users have dashboard access for **${guild.name}**:\n\n${userNameList}`,
|
||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { botControlCmd } from "../types";
|
import { botControlCmd } from "../types";
|
||||||
import { isOwnerPreFilter } from "../../../pluginUtils";
|
import { isOwnerPreFilter } from "../../../pluginUtils";
|
||||||
import { getActiveReload, setActiveReload } from "../activeReload";
|
import { getActiveReload, setActiveReload } from "../activeReload";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export const ReloadGlobalPluginsCmd = botControlCmd({
|
export const ReloadGlobalPluginsCmd = botControlCmd({
|
||||||
trigger: "bot_reload_global_plugins",
|
trigger: "bot_reload_global_plugins",
|
||||||
|
@ -13,7 +14,7 @@ export const ReloadGlobalPluginsCmd = botControlCmd({
|
||||||
if (getActiveReload()) return;
|
if (getActiveReload()) return;
|
||||||
|
|
||||||
setActiveReload((message.channel as TextChannel).guild?.id, message.channel.id);
|
setActiveReload((message.channel as TextChannel).guild?.id, message.channel.id);
|
||||||
await message.channel.createMessage("Reloading global plugins...");
|
await message.channel.send("Reloading global plugins...");
|
||||||
|
|
||||||
pluginData.getKnubInstance().reloadGlobalContext();
|
pluginData.getKnubInstance().reloadGlobalContext();
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { botControlCmd } from "../types";
|
import { botControlCmd } from "../types";
|
||||||
import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export const ReloadServerCmd = botControlCmd({
|
export const ReloadServerCmd = botControlCmd({
|
||||||
trigger: ["reload_server", "reload_guild"],
|
trigger: ["reload_server", "reload_guild"],
|
||||||
|
@ -14,19 +15,19 @@ export const ReloadServerCmd = botControlCmd({
|
||||||
},
|
},
|
||||||
|
|
||||||
async run({ pluginData, message: msg, args }) {
|
async run({ pluginData, message: msg, args }) {
|
||||||
if (!pluginData.client.guilds.has(args.guildId)) {
|
if (!pluginData.client.guilds.cache.has(args.guildId)) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "I am not in that guild");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "I am not in that guild");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await pluginData.getKnubInstance().reloadGuild(args.guildId);
|
await pluginData.getKnubInstance().reloadGuild(args.guildId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
sendErrorMessage(pluginData, msg.channel, `Failed to reload guild: ${e.message}`);
|
sendErrorMessage(pluginData, msg.channel as TextChannel, `Failed to reload guild: ${e.message}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const guild = pluginData.client.guilds.get(args.guildId);
|
const guild = await pluginData.client.guilds.fetch(args.guildId);
|
||||||
sendSuccessMessage(pluginData, msg.channel, `Reloaded guild **${guild?.name || "???"}**`);
|
sendSuccessMessage(pluginData, msg.channel as TextChannel, `Reloaded guild **${guild?.name || "???"}**`);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { botControlCmd } from "../types";
|
||||||
import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
import { isOwnerPreFilter, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { ApiPermissions } from "@shared/apiPermissions";
|
import { ApiPermissions } from "@shared/apiPermissions";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export const RemoveDashboardUserCmd = botControlCmd({
|
export const RemoveDashboardUserCmd = botControlCmd({
|
||||||
trigger: ["remove_dashboard_user"],
|
trigger: ["remove_dashboard_user"],
|
||||||
|
@ -18,7 +19,7 @@ export const RemoveDashboardUserCmd = botControlCmd({
|
||||||
async run({ pluginData, message: msg, args }) {
|
async run({ pluginData, message: msg, args }) {
|
||||||
const guild = await pluginData.state.allowedGuilds.find(args.guildId);
|
const guild = await pluginData.state.allowedGuilds.find(args.guildId);
|
||||||
if (!guild) {
|
if (!guild) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Server is not using Zeppelin");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "Server is not using Zeppelin");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +40,7 @@ export const RemoveDashboardUserCmd = botControlCmd({
|
||||||
);
|
);
|
||||||
sendSuccessMessage(
|
sendSuccessMessage(
|
||||||
pluginData,
|
pluginData,
|
||||||
msg.channel,
|
msg.channel as TextChannel,
|
||||||
`The following users were removed from the dashboard for **${guild.name}**:\n\n${userNameList}`,
|
`The following users were removed from the dashboard for **${guild.name}**:\n\n${userNameList}`,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { isOwnerPreFilter } from "../../../pluginUtils";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import escapeStringRegexp from "escape-string-regexp";
|
import escapeStringRegexp from "escape-string-regexp";
|
||||||
import { createChunkedMessage, getUser, sorter } from "../../../utils";
|
import { createChunkedMessage, getUser, sorter } from "../../../utils";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export const ServersCmd = botControlCmd({
|
export const ServersCmd = botControlCmd({
|
||||||
trigger: ["servers", "guilds"],
|
trigger: ["servers", "guilds"],
|
||||||
|
@ -23,7 +24,7 @@ export const ServersCmd = botControlCmd({
|
||||||
const showList = Boolean(args.all || args.initialized || args.uninitialized || args.search);
|
const showList = Boolean(args.all || args.initialized || args.uninitialized || args.search);
|
||||||
const search = args.search ? new RegExp([...args.search].map(s => escapeStringRegexp(s)).join(".*"), "i") : null;
|
const search = args.search ? new RegExp([...args.search].map(s => escapeStringRegexp(s)).join(".*"), "i") : null;
|
||||||
|
|
||||||
const joinedGuilds = Array.from(pluginData.client.guilds.values());
|
const joinedGuilds = Array.from(pluginData.client.guilds.cache.values());
|
||||||
const loadedGuilds = pluginData.getKnubInstance().getLoadedGuilds();
|
const loadedGuilds = pluginData.getKnubInstance().getLoadedGuilds();
|
||||||
const loadedGuildsMap = loadedGuilds.reduce((map, guildData) => map.set(guildData.guildId, guildData), new Map());
|
const loadedGuildsMap = loadedGuilds.reduce((map, guildData) => map.set(guildData.guildId, guildData), new Map());
|
||||||
|
|
||||||
|
@ -50,16 +51,16 @@ export const ServersCmd = botControlCmd({
|
||||||
const owner = getUser(pluginData.client, g.ownerID);
|
const owner = getUser(pluginData.client, g.ownerID);
|
||||||
return `\`${paddedId}\` **${g.name}** (${g.memberCount} members) (owner **${owner.username}#${owner.discriminator}** \`${owner.id}\`)`;
|
return `\`${paddedId}\` **${g.name}** (${g.memberCount} members) (owner **${owner.username}#${owner.discriminator}** \`${owner.id}\`)`;
|
||||||
});
|
});
|
||||||
createChunkedMessage(msg.channel, lines.join("\n"));
|
createChunkedMessage(msg.channel as TextChannel, lines.join("\n"));
|
||||||
} else {
|
} else {
|
||||||
msg.channel.createMessage("No servers matched the filters");
|
msg.channel.send("No servers matched the filters");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const total = joinedGuilds.length;
|
const total = joinedGuilds.length;
|
||||||
const initialized = joinedGuilds.filter(g => loadedGuildsMap.has(g.id)).length;
|
const initialized = joinedGuilds.filter(g => loadedGuildsMap.has(g.id)).length;
|
||||||
const unInitialized = total - initialized;
|
const unInitialized = total - initialized;
|
||||||
|
|
||||||
msg.channel.createMessage(
|
msg.channel.send(
|
||||||
`I am on **${total} total servers**, of which **${initialized} are initialized** and **${unInitialized} are not initialized**`,
|
`I am on **${total} total servers**, of which **${initialized} are initialized** and **${unInitialized} are not initialized**`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ export async function censorMessage(
|
||||||
pluginData.state.serverLogs.ignoreLog(LogType.MESSAGE_DELETE, savedMessage.id);
|
pluginData.state.serverLogs.ignoreLog(LogType.MESSAGE_DELETE, savedMessage.id);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const channel = pluginData.guild.channels.resolve(savedMessage.channel_id) as TextChannel
|
const channel = pluginData.guild.channels.resolve(savedMessage.channel_id) as TextChannel;
|
||||||
await channel.messages.delete(savedMessage.id);
|
await channel.messages.delete(savedMessage.id);
|
||||||
} catch {
|
} catch {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -104,6 +104,15 @@ export const ArchiveChannelCmd = channelArchiverCmd({
|
||||||
result += `\n\n${archiveLines.join("\n")}\n`;
|
result += `\n\n${archiveLines.join("\n")}\n`;
|
||||||
|
|
||||||
progressMsg.delete().catch(noop);
|
progressMsg.delete().catch(noop);
|
||||||
msg.channel.send({ content: "Archive created!", files: [{attachment: Buffer.from(result), name: `archive-${args.channel.name}-${moment.utc().format("YYYY-MM-DD-HH-mm-ss")}.txt`}], split: false });
|
msg.channel.send({
|
||||||
|
content: "Archive created!",
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
attachment: Buffer.from(result),
|
||||||
|
name: `archive-${args.channel.name}-${moment.utc().format("YYYY-MM-DD-HH-mm-ss")}.txt`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
split: false,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,7 +18,10 @@ export async function rehostAttachment(attachment: MessageAttachment, targetChan
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const content: MessageOptions = { content: `Rehost of attachment ${attachment.id}`, files: [{ name: attachment.name ? attachment.name : undefined, attachment: await fsp.readFile(downloaded.path)}]}
|
const content: MessageOptions = {
|
||||||
|
content: `Rehost of attachment ${attachment.id}`,
|
||||||
|
files: [{ name: attachment.name ? attachment.name : undefined, attachment: await fsp.readFile(downloaded.path) }],
|
||||||
|
};
|
||||||
const rehostMessage = await targetChannel.send({ content, split: false });
|
const rehostMessage = await targetChannel.send({ content, split: false });
|
||||||
return rehostMessage.attachments.values()[0].url;
|
return rehostMessage.attachments.values()[0].url;
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
@ -60,11 +60,9 @@ export async function handleCompanionPermissions(
|
||||||
for (const [channelId, permissions] of permsToSet) {
|
for (const [channelId, permissions] of permsToSet) {
|
||||||
const channel = pluginData.guild.channels.cache.get(channelId);
|
const channel = pluginData.guild.channels.cache.get(channelId);
|
||||||
if (!channel || !(channel instanceof TextChannel)) continue;
|
if (!channel || !(channel instanceof TextChannel)) continue;
|
||||||
await channel.updateOverwrite(
|
await channel.updateOverwrite(userId, new Permissions(BigInt(permissions)).serialize(), {
|
||||||
userId,
|
reason: `Companion Channel for ${voiceChannel!.id} | User Joined`,
|
||||||
new Permissions(BigInt(permissions)).serialize(),
|
});
|
||||||
{reason: `Companion Channel for ${voiceChannel!.id} | User Joined`},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (isDiscordRESTError(e) && e.code === 50001) {
|
if (isDiscordRESTError(e) && e.code === 50001) {
|
||||||
|
|
|
@ -128,13 +128,9 @@ export const AddCounterCmd = typedGuildCommand<CountersPluginType>()({
|
||||||
`Added ${amount} to **${counterName}** for <@!${user.id}> in <#${channel.id}>. The value is now ${newValue}.`,
|
`Added ${amount} to **${counterName}** for <@!${user.id}> in <#${channel.id}>. The value is now ${newValue}.`,
|
||||||
);
|
);
|
||||||
} else if (channel) {
|
} else if (channel) {
|
||||||
message.channel.send(
|
message.channel.send(`Added ${amount} to **${counterName}** in <#${channel.id}>. The value is now ${newValue}.`);
|
||||||
`Added ${amount} to **${counterName}** in <#${channel.id}>. The value is now ${newValue}.`,
|
|
||||||
);
|
|
||||||
} else if (user) {
|
} else if (user) {
|
||||||
message.channel.send(
|
message.channel.send(`Added ${amount} to **${counterName}** for <@!${user.id}>. The value is now ${newValue}.`);
|
||||||
`Added ${amount} to **${counterName}** for <@!${user.id}>. The value is now ${newValue}.`,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
message.channel.send(`Added ${amount} to **${counterName}**. The value is now ${newValue}.`);
|
message.channel.send(`Added ${amount} to **${counterName}**. The value is now ${newValue}.`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,6 @@ export async function addRoleAction(
|
||||||
|
|
||||||
const rolesToAdd = Array.isArray(action.role) ? action.role : [action.role];
|
const rolesToAdd = Array.isArray(action.role) ? action.role : [action.role];
|
||||||
await target.edit({
|
await target.edit({
|
||||||
roles: Array.from(new Set([...target.roles, ...rolesToAdd])),
|
roles: Array.from(new Set([...target.roles.cache.array(), ...rolesToAdd])),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { CustomEventsPluginType } from "../types";
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { renderTemplate } from "../../../templateFormatter";
|
import { renderTemplate } from "../../../templateFormatter";
|
||||||
import { ActionError } from "../ActionError";
|
import { ActionError } from "../ActionError";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export const MessageAction = t.type({
|
export const MessageAction = t.type({
|
||||||
type: t.literal("message"),
|
type: t.literal("message"),
|
||||||
|
@ -21,5 +22,5 @@ export async function messageAction(
|
||||||
if (!targetChannel) throw new ActionError("Unknown target channel");
|
if (!targetChannel) throw new ActionError("Unknown target channel");
|
||||||
if (!(targetChannel instanceof TextChannel)) throw new ActionError("Target channel is not a text channel");
|
if (!(targetChannel instanceof TextChannel)) throw new ActionError("Target channel is not a text channel");
|
||||||
|
|
||||||
await targetChannel.createMessage({ content: action.content });
|
await targetChannel.send({ content: action.content });
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { renderTemplate } from "../../../templateFormatter";
|
||||||
import { resolveMember } from "../../../utils";
|
import { resolveMember } from "../../../utils";
|
||||||
import { ActionError } from "../ActionError";
|
import { ActionError } from "../ActionError";
|
||||||
import { canActOn } from "../../../pluginUtils";
|
import { canActOn } from "../../../pluginUtils";
|
||||||
|
import { VoiceChannel } from "discord.js";
|
||||||
|
|
||||||
export const MoveToVoiceChannelAction = t.type({
|
export const MoveToVoiceChannelAction = t.type({
|
||||||
type: t.literal("move_to_vc"),
|
type: t.literal("move_to_vc"),
|
||||||
|
@ -33,8 +34,8 @@ export async function moveToVoiceChannelAction(
|
||||||
if (!targetChannel) throw new ActionError("Unknown target channel");
|
if (!targetChannel) throw new ActionError("Unknown target channel");
|
||||||
if (!(targetChannel instanceof VoiceChannel)) throw new ActionError("Target channel is not a voice channel");
|
if (!(targetChannel instanceof VoiceChannel)) throw new ActionError("Target channel is not a voice channel");
|
||||||
|
|
||||||
if (!target.voiceState.channelID) return;
|
if (!target.voice.channelID) return;
|
||||||
await target.edit({
|
await target.edit({
|
||||||
channelID: targetChannel.id,
|
channel: targetChannel.id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,11 +30,8 @@ export async function setChannelPermissionOverridesAction(
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const override of action.overrides) {
|
for (const override of action.overrides) {
|
||||||
await channel.editPermission(
|
await channel.overwritePermissions(
|
||||||
override.id,
|
[{ id: override.id, allow: BigInt(override.allow), deny: BigInt(override.deny), type: override.type }],
|
||||||
override.allow,
|
|
||||||
override.deny,
|
|
||||||
override.type,
|
|
||||||
`Custom event: ${event.name}`,
|
`Custom event: ${event.name}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { messageAction } from "../actions/messageAction";
|
||||||
import { makeRoleMentionableAction } from "../actions/makeRoleMentionableAction";
|
import { makeRoleMentionableAction } from "../actions/makeRoleMentionableAction";
|
||||||
import { makeRoleUnmentionableAction } from "../actions/makeRoleUnmentionableAction";
|
import { makeRoleUnmentionableAction } from "../actions/makeRoleUnmentionableAction";
|
||||||
import { setChannelPermissionOverridesAction } from "../actions/setChannelPermissionOverrides";
|
import { setChannelPermissionOverridesAction } from "../actions/setChannelPermissionOverrides";
|
||||||
|
import { Message, TextChannel } from "discord.js";
|
||||||
|
|
||||||
export async function runEvent(
|
export async function runEvent(
|
||||||
pluginData: GuildPluginData<CustomEventsPluginType>,
|
pluginData: GuildPluginData<CustomEventsPluginType>,
|
||||||
|
@ -38,7 +39,7 @@ export async function runEvent(
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof ActionError) {
|
if (e instanceof ActionError) {
|
||||||
if (event.trigger.type === "command") {
|
if (event.trigger.type === "command") {
|
||||||
sendErrorMessage(pluginData, (eventData.msg as Message).channel, e.message);
|
sendErrorMessage(pluginData, (eventData.msg as Message).channel as TextChannel, e.message);
|
||||||
} else {
|
} else {
|
||||||
// TODO: Where to log action errors from other kinds of triggers?
|
// TODO: Where to log action errors from other kinds of triggers?
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { zeppelinGlobalPlugin } from "../ZeppelinPluginBlueprint";
|
||||||
import { BasePluginType, typedGlobalEventListener, GlobalPluginData } from "knub";
|
import { BasePluginType, typedGlobalEventListener, GlobalPluginData } from "knub";
|
||||||
import * as t from "io-ts";
|
import * as t from "io-ts";
|
||||||
import { AllowedGuilds } from "../../data/AllowedGuilds";
|
import { AllowedGuilds } from "../../data/AllowedGuilds";
|
||||||
|
import { Guild } from "discord.js";
|
||||||
|
|
||||||
interface GuildAccessMonitorPluginType extends BasePluginType {
|
interface GuildAccessMonitorPluginType extends BasePluginType {
|
||||||
config: {};
|
config: {};
|
||||||
|
@ -27,7 +28,7 @@ export const GuildAccessMonitorPlugin = zeppelinGlobalPlugin<GuildAccessMonitorP
|
||||||
|
|
||||||
events: [
|
events: [
|
||||||
typedGlobalEventListener<GuildAccessMonitorPluginType>()({
|
typedGlobalEventListener<GuildAccessMonitorPluginType>()({
|
||||||
event: "guildAvailable",
|
event: "guildCreate",
|
||||||
listener({ pluginData, args: { guild } }) {
|
listener({ pluginData, args: { guild } }) {
|
||||||
checkGuild(pluginData, guild);
|
checkGuild(pluginData, guild);
|
||||||
},
|
},
|
||||||
|
@ -39,7 +40,7 @@ export const GuildAccessMonitorPlugin = zeppelinGlobalPlugin<GuildAccessMonitorP
|
||||||
},
|
},
|
||||||
|
|
||||||
afterLoad(pluginData) {
|
afterLoad(pluginData) {
|
||||||
for (const guild of pluginData.client.guilds.values()) {
|
for (const guild of pluginData.client.guilds.cache.values()) {
|
||||||
checkGuild(pluginData, guild);
|
checkGuild(pluginData, guild);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -54,9 +54,7 @@ export const FollowCmd = locateUserCmd({
|
||||||
sendSuccessMessage(
|
sendSuccessMessage(
|
||||||
pluginData,
|
pluginData,
|
||||||
msg.channel,
|
msg.channel,
|
||||||
`Every time <@${args.member.id}> joins or switches VC in the next ${humanizeDuration(
|
`Every time <@${args.member.id}> joins or switches VC in the next ${humanizeDuration(time)} i will notify you`,
|
||||||
time,
|
|
||||||
)} i will notify you`,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -13,7 +13,7 @@ export async function moveMember(
|
||||||
if (modMember.voice.channelID != null) {
|
if (modMember.voice.channelID != null) {
|
||||||
try {
|
try {
|
||||||
await modMember.edit({
|
await modMember.edit({
|
||||||
channel: target.voice.channelID
|
channel: target.voice.channelID,
|
||||||
});
|
});
|
||||||
} catch {
|
} catch {
|
||||||
sendErrorMessage(pluginData, errorChannel, "Failed to move you. Are you in a voice channel?");
|
sendErrorMessage(pluginData, errorChannel, "Failed to move you. Are you in a voice channel?");
|
||||||
|
|
|
@ -10,13 +10,15 @@ export const LogsVoiceStateUpdateEvt = logsEvt({
|
||||||
const newChannel = meta.args.newState.channel;
|
const newChannel = meta.args.newState.channel;
|
||||||
const member = meta.args.newState.member ?? meta.args.oldState.member!;
|
const member = meta.args.newState.member ?? meta.args.oldState.member!;
|
||||||
|
|
||||||
if (!newChannel) { // Leave evt
|
if (!newChannel) {
|
||||||
|
// Leave evt
|
||||||
meta.pluginData.state.guildLogs.log(LogType.VOICE_CHANNEL_LEAVE, {
|
meta.pluginData.state.guildLogs.log(LogType.VOICE_CHANNEL_LEAVE, {
|
||||||
member: stripObjectToScalars(member, ["user", "roles"]),
|
member: stripObjectToScalars(member, ["user", "roles"]),
|
||||||
oldChannel: stripObjectToScalars(oldChannel),
|
oldChannel: stripObjectToScalars(oldChannel),
|
||||||
newChannel: stripObjectToScalars(newChannel),
|
newChannel: stripObjectToScalars(newChannel),
|
||||||
});
|
});
|
||||||
} else if (!oldChannel) { // Join Evt
|
} else if (!oldChannel) {
|
||||||
|
// Join Evt
|
||||||
meta.pluginData.state.guildLogs.log(LogType.VOICE_CHANNEL_JOIN, {
|
meta.pluginData.state.guildLogs.log(LogType.VOICE_CHANNEL_JOIN, {
|
||||||
member: stripObjectToScalars(member, ["user", "roles"]),
|
member: stripObjectToScalars(member, ["user", "roles"]),
|
||||||
oldChannel: stripObjectToScalars(oldChannel),
|
oldChannel: stripObjectToScalars(oldChannel),
|
||||||
|
@ -29,6 +31,5 @@ export const LogsVoiceStateUpdateEvt = logsEvt({
|
||||||
newChannel: stripObjectToScalars(newChannel),
|
newChannel: stripObjectToScalars(newChannel),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,11 +16,7 @@ export const SavePinsToDBCmd = messageSaverCmd({
|
||||||
await msg.channel.send(`Saving pins from <#${args.channel.id}>...`);
|
await msg.channel.send(`Saving pins from <#${args.channel.id}>...`);
|
||||||
|
|
||||||
const pins = await args.channel.messages.fetchPinned();
|
const pins = await args.channel.messages.fetchPinned();
|
||||||
const { savedCount, failed } = await saveMessagesToDB(
|
const { savedCount, failed } = await saveMessagesToDB(pluginData, args.channel, pins.keyArray());
|
||||||
pluginData,
|
|
||||||
args.channel,
|
|
||||||
pins.keyArray(),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (failed.length) {
|
if (failed.length) {
|
||||||
sendSuccessMessage(
|
sendSuccessMessage(
|
||||||
|
|
|
@ -45,6 +45,7 @@ import { onModActionsEvent } from "./functions/onModActionsEvent";
|
||||||
import { offModActionsEvent } from "./functions/offModActionsEvent";
|
import { offModActionsEvent } from "./functions/offModActionsEvent";
|
||||||
import { updateCase } from "./functions/updateCase";
|
import { updateCase } from "./functions/updateCase";
|
||||||
import { Queue } from "../../Queue";
|
import { Queue } from "../../Queue";
|
||||||
|
import { GuildMember, Message } from "discord.js";
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
config: {
|
config: {
|
||||||
|
@ -158,13 +159,13 @@ export const ModActionsPlugin = zeppelinGuildPlugin<ModActionsPluginType>()({
|
||||||
|
|
||||||
public: {
|
public: {
|
||||||
warnMember(pluginData) {
|
warnMember(pluginData) {
|
||||||
return (member: Member, reason: string, warnOptions?: WarnOptions) => {
|
return (member: GuildMember, reason: string, warnOptions?: WarnOptions) => {
|
||||||
warnMember(pluginData, member, reason, warnOptions);
|
warnMember(pluginData, member, reason, warnOptions);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
kickMember(pluginData) {
|
kickMember(pluginData) {
|
||||||
return (member: Member, reason: string, kickOptions?: KickOptions) => {
|
return (member: GuildMember, reason: string, kickOptions?: KickOptions) => {
|
||||||
kickMember(pluginData, member, reason, kickOptions);
|
kickMember(pluginData, member, reason, kickOptions);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
|
@ -59,7 +59,7 @@ export const AddCaseCmd = modActionsCmd({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const reason = formatReasonWithAttachments(args.reason, msg.attachments);
|
const reason = formatReasonWithAttachments(args.reason, msg.attachments.array());
|
||||||
|
|
||||||
// Create the case
|
// Create the case
|
||||||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { isBanned } from "../functions/isBanned";
|
||||||
import { readContactMethodsFromArgs } from "../functions/readContactMethodsFromArgs";
|
import { readContactMethodsFromArgs } from "../functions/readContactMethodsFromArgs";
|
||||||
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
|
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
|
||||||
import { banUserId } from "../functions/banUserId";
|
import { banUserId } from "../functions/banUserId";
|
||||||
import { getMemberLevel, waitForReaction } from "knub/dist/helpers";
|
import { getMemberLevel } from "knub/dist/helpers";
|
||||||
import humanizeDuration from "humanize-duration";
|
import humanizeDuration from "humanize-duration";
|
||||||
import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin";
|
import { CasesPlugin } from "../../../plugins/Cases/CasesPlugin";
|
||||||
import { CaseTypes } from "../../../data/CaseTypes";
|
import { CaseTypes } from "../../../data/CaseTypes";
|
||||||
|
@ -49,7 +49,7 @@ export const BanCmd = modActionsCmd({
|
||||||
}
|
}
|
||||||
const time = args["time"] ? args["time"] : null;
|
const time = args["time"] ? args["time"] : null;
|
||||||
|
|
||||||
const reason = formatReasonWithAttachments(args.reason, msg.attachments);
|
const reason = formatReasonWithAttachments(args.reason, msg.attachments.array());
|
||||||
const memberToBan = await resolveMember(pluginData.client, pluginData.guild, user.id);
|
const memberToBan = await resolveMember(pluginData.client, pluginData.guild, user.id);
|
||||||
// The moderator who did the action is the message author or, if used, the specified -mod
|
// The moderator who did the action is the message author or, if used, the specified -mod
|
||||||
let mod = msg.member;
|
let mod = msg.member;
|
||||||
|
@ -76,11 +76,11 @@ export const BanCmd = modActionsCmd({
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ask the mod if we should update the existing ban
|
// Ask the mod if we should update the existing ban
|
||||||
const alreadyBannedMsg = await msg.channel.createMessage("User is already banned, update ban?");
|
const alreadyBannedMsg = await msg.channel.send("User is already banned, update ban?");
|
||||||
const reply = await waitForReaction(pluginData.client, alreadyBannedMsg, ["✅", "❌"], msg.author.id);
|
const reply = false; // await waitForReaction(pluginData.client, alreadyBannedMsg, ["✅", "❌"], msg.author.id); FIXME waiting on waitForButton
|
||||||
|
|
||||||
alreadyBannedMsg.delete().catch(noop);
|
alreadyBannedMsg.delete().catch(noop);
|
||||||
if (!reply || reply.name === "❌") {
|
if (!reply /* || reply.name === "❌"*/) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "User already banned, update cancelled by moderator");
|
sendErrorMessage(pluginData, msg.channel, "User already banned, update cancelled by moderator");
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
return;
|
return;
|
||||||
|
@ -124,11 +124,11 @@ export const BanCmd = modActionsCmd({
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Ask the mod if we should upgrade to a forceban as the user is not on the server
|
// Ask the mod if we should upgrade to a forceban as the user is not on the server
|
||||||
const notOnServerMsg = await msg.channel.createMessage("User not found on the server, forceban instead?");
|
const notOnServerMsg = await msg.channel.send("User not found on the server, forceban instead?");
|
||||||
const reply = await waitForReaction(pluginData.client, notOnServerMsg, ["✅", "❌"], msg.author.id);
|
const reply = false; // await waitForReaction(pluginData.client, notOnServerMsg, ["✅", "❌"], msg.author.id); Waiting for waitForButton
|
||||||
|
|
||||||
notOnServerMsg.delete().catch(noop);
|
notOnServerMsg.delete().catch(noop);
|
||||||
if (!reply || reply.name === "❌") {
|
if (!reply /*|| reply.name === "❌"*/) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "User not on server, ban cancelled by moderator");
|
sendErrorMessage(pluginData, msg.channel, "User not on server, ban cancelled by moderator");
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -24,6 +24,6 @@ export const CaseCmd = modActionsCmd({
|
||||||
|
|
||||||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||||
const embed = await casesPlugin.getCaseEmbed(theCase.id, msg.author.id);
|
const embed = await casesPlugin.getCaseEmbed(theCase.id, msg.author.id);
|
||||||
msg.channel.createMessage(embed);
|
msg.channel.send(embed);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { getChunkedEmbedFields } from "../../../utils/getChunkedEmbedFields";
|
||||||
import { getDefaultPrefix } from "knub/dist/commands/commandUtils";
|
import { getDefaultPrefix } from "knub/dist/commands/commandUtils";
|
||||||
import { getGuildPrefix } from "../../../utils/getGuildPrefix";
|
import { getGuildPrefix } from "../../../utils/getGuildPrefix";
|
||||||
import { createPaginatedMessage } from "../../../utils/createPaginatedMessage";
|
import { createPaginatedMessage } from "../../../utils/createPaginatedMessage";
|
||||||
|
import { MessageEmbedOptions, User } from "discord.js";
|
||||||
|
|
||||||
const opts = {
|
const opts = {
|
||||||
mod: ct.userId({ option: true }),
|
mod: ct.userId({ option: true }),
|
||||||
|
@ -55,10 +56,10 @@ export const CasesModCmd = modActionsCmd({
|
||||||
const lastCaseNum = page * casesPerPage;
|
const lastCaseNum = page * casesPerPage;
|
||||||
const title = `Most recent cases ${firstCaseNum}-${lastCaseNum} of ${totalCases} by ${modName}`;
|
const title = `Most recent cases ${firstCaseNum}-${lastCaseNum} of ${totalCases} by ${modName}`;
|
||||||
|
|
||||||
const embed: EmbedOptions = {
|
const embed: MessageEmbedOptions = {
|
||||||
author: {
|
author: {
|
||||||
name: title,
|
name: title,
|
||||||
icon_url: mod instanceof User ? mod.avatarURL || mod.defaultAvatarURL : undefined,
|
iconURL: mod instanceof User ? mod.avatarURL() || mod.defaultAvatarURL : undefined,
|
||||||
},
|
},
|
||||||
fields: [
|
fields: [
|
||||||
...getChunkedEmbedFields(emptyEmbedValue, lines.join("\n")),
|
...getChunkedEmbedFields(emptyEmbedValue, lines.join("\n")),
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { getGuildPrefix } from "../../../utils/getGuildPrefix";
|
||||||
import { getChunkedEmbedFields } from "../../../utils/getChunkedEmbedFields";
|
import { getChunkedEmbedFields } from "../../../utils/getChunkedEmbedFields";
|
||||||
import { asyncMap } from "../../../utils/async";
|
import { asyncMap } from "../../../utils/async";
|
||||||
import { CaseTypes } from "../../../data/CaseTypes";
|
import { CaseTypes } from "../../../data/CaseTypes";
|
||||||
|
import { MessageEmbedOptions, User } from "discord.js";
|
||||||
|
|
||||||
const opts = {
|
const opts = {
|
||||||
expand: ct.bool({ option: true, isSwitch: true, shortcut: "e" }),
|
expand: ct.bool({ option: true, isSwitch: true, shortcut: "e" }),
|
||||||
|
@ -75,13 +76,13 @@ export const CasesUserCmd = modActionsCmd({
|
||||||
: `${user.username}#${user.discriminator}`;
|
: `${user.username}#${user.discriminator}`;
|
||||||
|
|
||||||
if (cases.length === 0) {
|
if (cases.length === 0) {
|
||||||
msg.channel.createMessage(`No cases found for **${userName}**`);
|
msg.channel.send(`No cases found for **${userName}**`);
|
||||||
} else {
|
} else {
|
||||||
const casesToDisplay = args.hidden ? cases : normalCases;
|
const casesToDisplay = args.hidden ? cases : normalCases;
|
||||||
|
|
||||||
if (args.expand) {
|
if (args.expand) {
|
||||||
if (casesToDisplay.length > 8) {
|
if (casesToDisplay.length > 8) {
|
||||||
msg.channel.createMessage("Too many cases for expanded view. Please use compact view instead.");
|
msg.channel.send("Too many cases for expanded view. Please use compact view instead.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +90,7 @@ export const CasesUserCmd = modActionsCmd({
|
||||||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||||
for (const theCase of casesToDisplay) {
|
for (const theCase of casesToDisplay) {
|
||||||
const embed = await casesPlugin.getCaseEmbed(theCase.id);
|
const embed = await casesPlugin.getCaseEmbed(theCase.id);
|
||||||
msg.channel.createMessage(embed);
|
msg.channel.send(embed);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Compact view (= regular message with a preview of each case)
|
// Compact view (= regular message with a preview of each case)
|
||||||
|
@ -121,13 +122,13 @@ export const CasesUserCmd = modActionsCmd({
|
||||||
const chunkStart = i * linesPerChunk + 1;
|
const chunkStart = i * linesPerChunk + 1;
|
||||||
const chunkEnd = Math.min((i + 1) * linesPerChunk, lines.length);
|
const chunkEnd = Math.min((i + 1) * linesPerChunk, lines.length);
|
||||||
|
|
||||||
const embed: EmbedOptions = {
|
const embed: MessageEmbedOptions = {
|
||||||
author: {
|
author: {
|
||||||
name:
|
name:
|
||||||
lineChunks.length === 1
|
lineChunks.length === 1
|
||||||
? `Cases for ${userName} (${lines.length} total)`
|
? `Cases for ${userName} (${lines.length} total)`
|
||||||
: `Cases ${chunkStart}–${chunkEnd} of ${lines.length} for ${userName}`,
|
: `Cases ${chunkStart}–${chunkEnd} of ${lines.length} for ${userName}`,
|
||||||
icon_url: user instanceof User ? user.avatarURL || user.defaultAvatarURL : undefined,
|
icon_url: user instanceof User ? user.avatarURL() || user.defaultAvatarURL : undefined,
|
||||||
},
|
},
|
||||||
fields: [
|
fields: [
|
||||||
...getChunkedEmbedFields(emptyEmbedValue, linesInChunk.join("\n")),
|
...getChunkedEmbedFields(emptyEmbedValue, linesInChunk.join("\n")),
|
||||||
|
@ -135,7 +136,7 @@ export const CasesUserCmd = modActionsCmd({
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
msg.channel.createMessage({ embed });
|
msg.channel.send({ embed });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { LogType } from "../../../data/LogType";
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin";
|
import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin";
|
||||||
import { Case } from "../../../data/entities/Case";
|
import { Case } from "../../../data/entities/Case";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export const DeleteCaseCmd = modActionsCmd({
|
export const DeleteCaseCmd = modActionsCmd({
|
||||||
trigger: ["delete_case", "deletecase"],
|
trigger: ["delete_case", "deletecase"],
|
||||||
|
@ -49,7 +50,7 @@ export const DeleteCaseCmd = modActionsCmd({
|
||||||
if (!args.force) {
|
if (!args.force) {
|
||||||
const cases = pluginData.getPlugin(CasesPlugin);
|
const cases = pluginData.getPlugin(CasesPlugin);
|
||||||
const embedContent = await cases.getCaseEmbed(theCase);
|
const embedContent = await cases.getCaseEmbed(theCase);
|
||||||
message.channel.createMessage({
|
message.channel.send({
|
||||||
content: "Delete the following case? Answer 'Yes' to continue, 'No' to cancel.",
|
content: "Delete the following case? Answer 'Yes' to continue, 'No' to cancel.",
|
||||||
embed: embedContent.embed,
|
embed: embedContent.embed,
|
||||||
});
|
});
|
||||||
|
@ -62,7 +63,7 @@ export const DeleteCaseCmd = modActionsCmd({
|
||||||
);
|
);
|
||||||
const normalizedReply = (reply?.content || "").toLowerCase().trim();
|
const normalizedReply = (reply?.content || "").toLowerCase().trim();
|
||||||
if (normalizedReply !== "yes" && normalizedReply !== "y") {
|
if (normalizedReply !== "yes" && normalizedReply !== "y") {
|
||||||
message.channel.createMessage("Cancelled. Case was not deleted.");
|
message.channel.send("Cancelled. Case was not deleted.");
|
||||||
cancelled++;
|
cancelled++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,14 +61,17 @@ export const ForcebanCmd = modActionsCmd({
|
||||||
mod = args.mod;
|
mod = args.mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
const reason = formatReasonWithAttachments(args.reason, msg.attachments);
|
const reason = formatReasonWithAttachments(args.reason, msg.attachments.array());
|
||||||
|
|
||||||
ignoreEvent(pluginData, IgnoredEventType.Ban, user.id);
|
ignoreEvent(pluginData, IgnoredEventType.Ban, user.id);
|
||||||
pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_BAN, user.id);
|
pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_BAN, user.id);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// FIXME: Use banUserId()?
|
// FIXME: Use banUserId()?
|
||||||
await pluginData.guild.banMember(user.id, 1, reason != null ? encodeURIComponent(reason) : undefined);
|
await pluginData.guild.bans.create(user.id, {
|
||||||
|
days: 1,
|
||||||
|
reason: reason != null ? encodeURIComponent(reason) : undefined,
|
||||||
|
});
|
||||||
} catch {
|
} catch {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Failed to forceban member");
|
sendErrorMessage(pluginData, msg.channel, "Failed to forceban member");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { LogType } from "../../../data/LogType";
|
||||||
import { performance } from "perf_hooks";
|
import { performance } from "perf_hooks";
|
||||||
import { humanizeDurationShort } from "../../../humanizeDurationShort";
|
import { humanizeDurationShort } from "../../../humanizeDurationShort";
|
||||||
import { load } from "js-yaml";
|
import { load } from "js-yaml";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export const MassbanCmd = modActionsCmd({
|
export const MassbanCmd = modActionsCmd({
|
||||||
trigger: "massban",
|
trigger: "massban",
|
||||||
|
@ -35,14 +36,14 @@ export const MassbanCmd = modActionsCmd({
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ask for ban reason (cleaner this way instead of trying to cram it into the args)
|
// Ask for ban reason (cleaner this way instead of trying to cram it into the args)
|
||||||
msg.channel.createMessage("Ban reason? `cancel` to cancel");
|
msg.channel.send("Ban reason? `cancel` to cancel");
|
||||||
const banReasonReply = await waitForReply(pluginData.client, msg.channel as TextChannel, msg.author.id);
|
const banReasonReply = await waitForReply(pluginData.client, msg.channel as TextChannel, msg.author.id);
|
||||||
if (!banReasonReply || !banReasonReply.content || banReasonReply.content.toLowerCase().trim() === "cancel") {
|
if (!banReasonReply || !banReasonReply.content || banReasonReply.content.toLowerCase().trim() === "cancel") {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Cancelled");
|
sendErrorMessage(pluginData, msg.channel, "Cancelled");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const banReason = formatReasonWithAttachments(banReasonReply.content, msg.attachments);
|
const banReason = formatReasonWithAttachments(banReasonReply.content, msg.attachments.array());
|
||||||
|
|
||||||
// Verify we can act on each of the users specified
|
// Verify we can act on each of the users specified
|
||||||
for (const userId of args.userIds) {
|
for (const userId of args.userIds) {
|
||||||
|
@ -60,7 +61,7 @@ export const MassbanCmd = modActionsCmd({
|
||||||
pluginData.state.massbanQueue.length === 0
|
pluginData.state.massbanQueue.length === 0
|
||||||
? "Banning..."
|
? "Banning..."
|
||||||
: `Massban queued. Waiting for previous massban to finish (max wait ${maxWaitTimeFormatted}).`;
|
: `Massban queued. Waiting for previous massban to finish (max wait ${maxWaitTimeFormatted}).`;
|
||||||
const loadingMsg = await msg.channel.createMessage(initialLoadingText);
|
const loadingMsg = await msg.channel.send(initialLoadingText);
|
||||||
|
|
||||||
const waitTimeStart = performance.now();
|
const waitTimeStart = performance.now();
|
||||||
const waitingInterval = setInterval(() => {
|
const waitingInterval = setInterval(() => {
|
||||||
|
@ -95,7 +96,10 @@ export const MassbanCmd = modActionsCmd({
|
||||||
ignoreEvent(pluginData, IgnoredEventType.Ban, userId, 120 * 1000);
|
ignoreEvent(pluginData, IgnoredEventType.Ban, userId, 120 * 1000);
|
||||||
pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_BAN, userId, 120 * 1000);
|
pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_BAN, userId, 120 * 1000);
|
||||||
|
|
||||||
await pluginData.guild.banMember(userId, 1, banReason != null ? encodeURIComponent(banReason) : undefined);
|
await pluginData.guild.bans.create(userId, {
|
||||||
|
days: 1,
|
||||||
|
reason: banReason != null ? encodeURIComponent(banReason) : undefined,
|
||||||
|
});
|
||||||
|
|
||||||
await casesPlugin.createCase({
|
await casesPlugin.createCase({
|
||||||
userId,
|
userId,
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { waitForReply } from "knub/dist/helpers";
|
||||||
import { ignoreEvent } from "../functions/ignoreEvent";
|
import { ignoreEvent } from "../functions/ignoreEvent";
|
||||||
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export const MassunbanCmd = modActionsCmd({
|
export const MassunbanCmd = modActionsCmd({
|
||||||
trigger: "massunban",
|
trigger: "massunban",
|
||||||
|
@ -30,14 +31,14 @@ export const MassunbanCmd = modActionsCmd({
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ask for unban reason (cleaner this way instead of trying to cram it into the args)
|
// Ask for unban reason (cleaner this way instead of trying to cram it into the args)
|
||||||
msg.channel.createMessage("Unban reason? `cancel` to cancel");
|
msg.channel.send("Unban reason? `cancel` to cancel");
|
||||||
const unbanReasonReply = await waitForReply(pluginData.client, msg.channel as TextChannel, msg.author.id);
|
const unbanReasonReply = await waitForReply(pluginData.client, msg.channel as TextChannel, msg.author.id);
|
||||||
if (!unbanReasonReply || !unbanReasonReply.content || unbanReasonReply.content.toLowerCase().trim() === "cancel") {
|
if (!unbanReasonReply || !unbanReasonReply.content || unbanReasonReply.content.toLowerCase().trim() === "cancel") {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Cancelled");
|
sendErrorMessage(pluginData, msg.channel, "Cancelled");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unbanReason = formatReasonWithAttachments(unbanReasonReply.content, msg.attachments);
|
const unbanReason = formatReasonWithAttachments(unbanReasonReply.content, msg.attachments.array());
|
||||||
|
|
||||||
// Ignore automatic unban cases and logs for these users
|
// Ignore automatic unban cases and logs for these users
|
||||||
// We'll create our own cases below and post a single "mass unbanned" log instead
|
// We'll create our own cases below and post a single "mass unbanned" log instead
|
||||||
|
@ -48,7 +49,7 @@ export const MassunbanCmd = modActionsCmd({
|
||||||
});
|
});
|
||||||
|
|
||||||
// Show a loading indicator since this can take a while
|
// Show a loading indicator since this can take a while
|
||||||
const loadingMsg = await msg.channel.createMessage("Unbanning...");
|
const loadingMsg = await msg.channel.send("Unbanning...");
|
||||||
|
|
||||||
// Unban each user and count failed unbans (if any)
|
// Unban each user and count failed unbans (if any)
|
||||||
const failedUnbans: Array<{ userId: string; reason: UnbanFailReasons }> = [];
|
const failedUnbans: Array<{ userId: string; reason: UnbanFailReasons }> = [];
|
||||||
|
@ -60,7 +61,7 @@ export const MassunbanCmd = modActionsCmd({
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await pluginData.guild.unbanMember(userId, unbanReason != null ? encodeURIComponent(unbanReason) : undefined);
|
await pluginData.guild.bans.remove(userId, unbanReason != null ? encodeURIComponent(unbanReason) : undefined);
|
||||||
|
|
||||||
await casesPlugin.createCase({
|
await casesPlugin.createCase({
|
||||||
userId,
|
userId,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { waitForReply } from "knub/dist/helpers";
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
import { logger } from "../../../logger";
|
import { logger } from "../../../logger";
|
||||||
import { MutesPlugin } from "../../../plugins/Mutes/MutesPlugin";
|
import { MutesPlugin } from "../../../plugins/Mutes/MutesPlugin";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export const MassmuteCmd = modActionsCmd({
|
export const MassmuteCmd = modActionsCmd({
|
||||||
trigger: "massmute",
|
trigger: "massmute",
|
||||||
|
@ -28,7 +29,7 @@ export const MassmuteCmd = modActionsCmd({
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ask for mute reason
|
// Ask for mute reason
|
||||||
msg.channel.createMessage("Mute reason? `cancel` to cancel");
|
msg.channel.send("Mute reason? `cancel` to cancel");
|
||||||
const muteReasonReceived = await waitForReply(pluginData.client, msg.channel as TextChannel, msg.author.id);
|
const muteReasonReceived = await waitForReply(pluginData.client, msg.channel as TextChannel, msg.author.id);
|
||||||
if (
|
if (
|
||||||
!muteReasonReceived ||
|
!muteReasonReceived ||
|
||||||
|
@ -39,7 +40,7 @@ export const MassmuteCmd = modActionsCmd({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const muteReason = formatReasonWithAttachments(muteReasonReceived.content, msg.attachments);
|
const muteReason = formatReasonWithAttachments(muteReasonReceived.content, msg.attachments.array());
|
||||||
|
|
||||||
// Verify we can act upon all users
|
// Verify we can act upon all users
|
||||||
for (const userId of args.userIds) {
|
for (const userId of args.userIds) {
|
||||||
|
@ -58,7 +59,7 @@ export const MassmuteCmd = modActionsCmd({
|
||||||
});
|
});
|
||||||
|
|
||||||
// Show loading indicator
|
// Show loading indicator
|
||||||
const loadingMsg = await msg.channel.createMessage("Muting...");
|
const loadingMsg = await msg.channel.send("Muting...");
|
||||||
|
|
||||||
// Mute everyone and count fails
|
// Mute everyone and count fails
|
||||||
const modId = msg.author.id;
|
const modId = msg.author.id;
|
||||||
|
|
|
@ -1,16 +1,8 @@
|
||||||
import { modActionsCmd } from "../types";
|
import { modActionsCmd } from "../types";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { Case } from "../../../data/entities/Case";
|
import { canActOn, sendErrorMessage } from "../../../pluginUtils";
|
||||||
import { canActOn, hasPermission, sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
import { noop, resolveMember, resolveUser } from "../../../utils";
|
||||||
import { formatReasonWithAttachments } from "../functions/formatReasonWithAttachments";
|
|
||||||
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
|
||||||
import { LogType } from "../../../data/LogType";
|
|
||||||
import { CaseTypes } from "../../../data/CaseTypes";
|
|
||||||
import { errorMessage, noop, resolveMember, resolveUser, stripObjectToScalars } from "../../../utils";
|
|
||||||
import { isBanned } from "../functions/isBanned";
|
import { isBanned } from "../functions/isBanned";
|
||||||
import { waitForReaction } from "knub/dist/helpers";
|
|
||||||
import { readContactMethodsFromArgs } from "../functions/readContactMethodsFromArgs";
|
|
||||||
import { warnMember } from "../functions/warnMember";
|
|
||||||
|
|
||||||
import { actualMuteUserCmd } from "../functions/actualMuteUserCmd";
|
import { actualMuteUserCmd } from "../functions/actualMuteUserCmd";
|
||||||
|
|
||||||
|
@ -62,11 +54,11 @@ export const MuteCmd = modActionsCmd({
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// Ask the mod if we should upgrade to a forcemute as the user is not on the server
|
// Ask the mod if we should upgrade to a forcemute as the user is not on the server
|
||||||
const notOnServerMsg = await msg.channel.createMessage("User not found on the server, forcemute instead?");
|
const notOnServerMsg = await msg.channel.send("User not found on the server, forcemute instead?");
|
||||||
const reply = await waitForReaction(pluginData.client, notOnServerMsg, ["✅", "❌"], msg.author.id);
|
const reply = false; // await waitForReaction(pluginData.client, notOnServerMsg, ["✅", "❌"], msg.author.id); FIXME waiting on waitForButton
|
||||||
|
|
||||||
notOnServerMsg.delete().catch(noop);
|
notOnServerMsg.delete().catch(noop);
|
||||||
if (!reply || reply.name === "❌") {
|
if (!reply /*|| reply.name === "❌"*/) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "User not on server, mute cancelled by moderator");
|
sendErrorMessage(pluginData, msg.channel, "User not on server, mute cancelled by moderator");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,13 +25,13 @@ export const NoteCmd = modActionsCmd({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!args.note && msg.attachments.length === 0) {
|
if (!args.note && msg.attachments.size === 0) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Text or attachment required");
|
sendErrorMessage(pluginData, msg.channel, "Text or attachment required");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const userName = `${user.username}#${user.discriminator}`;
|
const userName = `${user.username}#${user.discriminator}`;
|
||||||
const reason = formatReasonWithAttachments(args.note, msg.attachments);
|
const reason = formatReasonWithAttachments(args.note, msg.attachments.array());
|
||||||
|
|
||||||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||||
const createdCase = await casesPlugin.createCase({
|
const createdCase = await casesPlugin.createCase({
|
||||||
|
|
|
@ -28,7 +28,7 @@ export const SoftbanCmd = modActionsCmd({
|
||||||
|
|
||||||
async run({ pluginData, message: msg, args }) {
|
async run({ pluginData, message: msg, args }) {
|
||||||
await actualKickMemberCmd(pluginData, msg, { clean: true, ...args });
|
await actualKickMemberCmd(pluginData, msg, { clean: true, ...args });
|
||||||
await msg.channel.createMessage(
|
await msg.channel.send(
|
||||||
"Softban will be removed in the future - please use the kick command with the `-clean` argument instead!",
|
"Softban will be removed in the future - please use the kick command with the `-clean` argument instead!",
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -45,11 +45,11 @@ export const UnbanCmd = modActionsCmd({
|
||||||
}
|
}
|
||||||
|
|
||||||
pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_UNBAN, user.id);
|
pluginData.state.serverLogs.ignoreLog(LogType.MEMBER_UNBAN, user.id);
|
||||||
const reason = formatReasonWithAttachments(args.reason, msg.attachments);
|
const reason = formatReasonWithAttachments(args.reason, msg.attachments.array());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ignoreEvent(pluginData, IgnoredEventType.Unban, user.id);
|
ignoreEvent(pluginData, IgnoredEventType.Unban, user.id);
|
||||||
await pluginData.guild.unbanMember(user.id, reason != null ? encodeURIComponent(reason) : undefined);
|
await pluginData.guild.bans.remove(user.id, reason != null ? encodeURIComponent(reason) : undefined);
|
||||||
} catch {
|
} catch {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Failed to unban member; are you sure they're banned?");
|
sendErrorMessage(pluginData, msg.channel, "Failed to unban member; are you sure they're banned?");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { resolveUser, resolveMember, noop } from "../../../utils";
|
||||||
import { MutesPlugin } from "../../../plugins/Mutes/MutesPlugin";
|
import { MutesPlugin } from "../../../plugins/Mutes/MutesPlugin";
|
||||||
import { actualUnmuteCmd } from "../functions/actualUnmuteUserCmd";
|
import { actualUnmuteCmd } from "../functions/actualUnmuteUserCmd";
|
||||||
import { isBanned } from "../functions/isBanned";
|
import { isBanned } from "../functions/isBanned";
|
||||||
import { waitForReaction } from "knub/dist/helpers";
|
|
||||||
|
|
||||||
const opts = {
|
const opts = {
|
||||||
mod: ct.member({ option: true }),
|
mod: ct.member({ option: true }),
|
||||||
|
@ -61,11 +60,11 @@ export const UnmuteCmd = modActionsCmd({
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// Ask the mod if we should upgrade to a forceunmute as the user is not on the server
|
// Ask the mod if we should upgrade to a forceunmute as the user is not on the server
|
||||||
const notOnServerMsg = await msg.channel.createMessage("User not found on the server, forceunmute instead?");
|
const notOnServerMsg = await msg.channel.send("User not found on the server, forceunmute instead?");
|
||||||
const reply = await waitForReaction(pluginData.client, notOnServerMsg, ["✅", "❌"], msg.author.id);
|
const reply = false; //await waitForReaction(pluginData.client, notOnServerMsg, ["✅", "❌"], msg.author.id); FIXME waiting on waitForButton
|
||||||
|
|
||||||
notOnServerMsg.delete().catch(noop);
|
notOnServerMsg.delete().catch(noop);
|
||||||
if (!reply || reply.name === "❌") {
|
if (!reply /*|| reply.name === "❌"*/) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "User not on server, unmute cancelled by moderator");
|
sendErrorMessage(pluginData, msg.channel, "User not on server, unmute cancelled by moderator");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,9 @@ import { LogType } from "../../../data/LogType";
|
||||||
import { CaseTypes } from "../../../data/CaseTypes";
|
import { CaseTypes } from "../../../data/CaseTypes";
|
||||||
import { errorMessage, resolveMember, resolveUser, stripObjectToScalars } from "../../../utils";
|
import { errorMessage, resolveMember, resolveUser, stripObjectToScalars } from "../../../utils";
|
||||||
import { isBanned } from "../functions/isBanned";
|
import { isBanned } from "../functions/isBanned";
|
||||||
import { waitForReaction } from "knub/dist/helpers";
|
|
||||||
import { readContactMethodsFromArgs } from "../functions/readContactMethodsFromArgs";
|
import { readContactMethodsFromArgs } from "../functions/readContactMethodsFromArgs";
|
||||||
import { warnMember } from "../functions/warnMember";
|
import { warnMember } from "../functions/warnMember";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export const WarnCmd = modActionsCmd({
|
export const WarnCmd = modActionsCmd({
|
||||||
trigger: "warn",
|
trigger: "warn",
|
||||||
|
@ -56,7 +56,7 @@ export const WarnCmd = modActionsCmd({
|
||||||
let mod = msg.member;
|
let mod = msg.member;
|
||||||
if (args.mod) {
|
if (args.mod) {
|
||||||
if (!(await hasPermission(pluginData, "can_act_as_other", { message: msg }))) {
|
if (!(await hasPermission(pluginData, "can_act_as_other", { message: msg }))) {
|
||||||
msg.channel.createMessage(errorMessage("You don't have permission to use -mod"));
|
msg.channel.send(errorMessage("You don't have permission to use -mod"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,19 +64,19 @@ export const WarnCmd = modActionsCmd({
|
||||||
}
|
}
|
||||||
|
|
||||||
const config = pluginData.config.get();
|
const config = pluginData.config.get();
|
||||||
const reason = formatReasonWithAttachments(args.reason, msg.attachments);
|
const reason = formatReasonWithAttachments(args.reason, msg.attachments.array());
|
||||||
|
|
||||||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||||
const priorWarnAmount = await casesPlugin.getCaseTypeAmountForUserId(memberToWarn.id, CaseTypes.Warn);
|
const priorWarnAmount = await casesPlugin.getCaseTypeAmountForUserId(memberToWarn.id, CaseTypes.Warn);
|
||||||
if (config.warn_notify_enabled && priorWarnAmount >= config.warn_notify_threshold) {
|
if (config.warn_notify_enabled && priorWarnAmount >= config.warn_notify_threshold) {
|
||||||
const tooManyWarningsMsg = await msg.channel.createMessage(
|
const tooManyWarningsMsg = await msg.channel.send(
|
||||||
config.warn_notify_message.replace("{priorWarnings}", `${priorWarnAmount}`),
|
config.warn_notify_message.replace("{priorWarnings}", `${priorWarnAmount}`),
|
||||||
);
|
);
|
||||||
|
|
||||||
const reply = await waitForReaction(pluginData.client, tooManyWarningsMsg, ["✅", "❌"], msg.author.id);
|
const reply = false; //await waitForReaction(pluginData.client, tooManyWarningsMsg, ["✅", "❌"], msg.author.id); FIXME waiting on waitForButton
|
||||||
tooManyWarningsMsg.delete();
|
tooManyWarningsMsg.delete();
|
||||||
if (!reply || reply.name === "❌") {
|
if (!reply /*|| reply.name === "❌"*/) {
|
||||||
msg.channel.createMessage(errorMessage("Warn cancelled by moderator"));
|
msg.channel.send(errorMessage("Warn cancelled by moderator"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { safeFindRelevantAuditLogEntry } from "../../../utils/safeFindRelevantAu
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
import { stripObjectToScalars, resolveUser, UnknownUser } from "../../../utils";
|
import { stripObjectToScalars, resolveUser, UnknownUser } from "../../../utils";
|
||||||
import { Case } from "../../../data/entities/Case";
|
import { Case } from "../../../data/entities/Case";
|
||||||
|
import { GuildAuditLogs, User } from "discord.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a BAN case automatically when a user is banned manually.
|
* Create a BAN case automatically when a user is banned manually.
|
||||||
|
@ -15,7 +16,8 @@ import { Case } from "../../../data/entities/Case";
|
||||||
*/
|
*/
|
||||||
export const CreateBanCaseOnManualBanEvt = modActionsEvt({
|
export const CreateBanCaseOnManualBanEvt = modActionsEvt({
|
||||||
event: "guildBanAdd",
|
event: "guildBanAdd",
|
||||||
async listener({ pluginData, args: { guild, user } }) {
|
async listener({ pluginData, args: { ban } }) {
|
||||||
|
const user = ban.user;
|
||||||
if (isEventIgnored(pluginData, IgnoredEventType.Ban, user.id)) {
|
if (isEventIgnored(pluginData, IgnoredEventType.Ban, user.id)) {
|
||||||
clearIgnoredEvents(pluginData, IgnoredEventType.Ban, user.id);
|
clearIgnoredEvents(pluginData, IgnoredEventType.Ban, user.id);
|
||||||
return;
|
return;
|
||||||
|
@ -23,7 +25,7 @@ export const CreateBanCaseOnManualBanEvt = modActionsEvt({
|
||||||
|
|
||||||
const relevantAuditLogEntry = await safeFindRelevantAuditLogEntry(
|
const relevantAuditLogEntry = await safeFindRelevantAuditLogEntry(
|
||||||
pluginData,
|
pluginData,
|
||||||
ErisConstants.AuditLogActions.MEMBER_BAN_ADD,
|
GuildAuditLogs.Actions.MEMBER_BAN_ADD as number,
|
||||||
user.id,
|
user.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -34,7 +36,7 @@ export const CreateBanCaseOnManualBanEvt = modActionsEvt({
|
||||||
let reason = "";
|
let reason = "";
|
||||||
|
|
||||||
if (relevantAuditLogEntry) {
|
if (relevantAuditLogEntry) {
|
||||||
const modId = relevantAuditLogEntry.user.id;
|
const modId = relevantAuditLogEntry.executor!.id;
|
||||||
const auditLogId = relevantAuditLogEntry.id;
|
const auditLogId = relevantAuditLogEntry.id;
|
||||||
|
|
||||||
mod = await resolveUser(pluginData.client, modId);
|
mod = await resolveUser(pluginData.client, modId);
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { LogType } from "../../../data/LogType";
|
||||||
import { resolveUser, stripObjectToScalars, UnknownUser } from "../../../utils";
|
import { resolveUser, stripObjectToScalars, UnknownUser } from "../../../utils";
|
||||||
import { safeFindRelevantAuditLogEntry } from "../../../utils/safeFindRelevantAuditLogEntry";
|
import { safeFindRelevantAuditLogEntry } from "../../../utils/safeFindRelevantAuditLogEntry";
|
||||||
import { Case } from "../../../data/entities/Case";
|
import { Case } from "../../../data/entities/Case";
|
||||||
|
import { GuildAuditLogs, User } from "discord.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a KICK case automatically when a user is kicked manually.
|
* Create a KICK case automatically when a user is kicked manually.
|
||||||
|
@ -24,7 +25,7 @@ export const CreateKickCaseOnManualKickEvt = modActionsEvt({
|
||||||
|
|
||||||
const kickAuditLogEntry = await safeFindRelevantAuditLogEntry(
|
const kickAuditLogEntry = await safeFindRelevantAuditLogEntry(
|
||||||
pluginData,
|
pluginData,
|
||||||
ErisConstants.AuditLogActions.MEMBER_KICK,
|
GuildAuditLogs.Actions.MEMBER_KICK as number,
|
||||||
member.id,
|
member.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -40,7 +41,7 @@ export const CreateKickCaseOnManualKickEvt = modActionsEvt({
|
||||||
`Tried to create duplicate case for audit log entry ${kickAuditLogEntry.id}, existing case id ${createdCase.id}`,
|
`Tried to create duplicate case for audit log entry ${kickAuditLogEntry.id}, existing case id ${createdCase.id}`,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
mod = await resolveUser(pluginData.client, kickAuditLogEntry.user.id);
|
mod = await resolveUser(pluginData.client, kickAuditLogEntry.executor!.id);
|
||||||
|
|
||||||
const config = mod instanceof UnknownUser ? pluginData.config.get() : await pluginData.config.getForUser(mod);
|
const config = mod instanceof UnknownUser ? pluginData.config.get() : await pluginData.config.getForUser(mod);
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ export const CreateKickCaseOnManualKickEvt = modActionsEvt({
|
||||||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||||
createdCase = await casesPlugin.createCase({
|
createdCase = await casesPlugin.createCase({
|
||||||
userId: member.id,
|
userId: member.id,
|
||||||
modId: kickAuditLogEntry.user.id,
|
modId: mod.id,
|
||||||
type: CaseTypes.Kick,
|
type: CaseTypes.Kick,
|
||||||
auditLogId: kickAuditLogEntry.id,
|
auditLogId: kickAuditLogEntry.id,
|
||||||
reason: kickAuditLogEntry.reason || undefined,
|
reason: kickAuditLogEntry.reason || undefined,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { safeFindRelevantAuditLogEntry } from "../../../utils/safeFindRelevantAu
|
||||||
import { stripObjectToScalars, resolveUser, UnknownUser } from "../../../utils";
|
import { stripObjectToScalars, resolveUser, UnknownUser } from "../../../utils";
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
import { Case } from "../../../data/entities/Case";
|
import { Case } from "../../../data/entities/Case";
|
||||||
|
import { GuildAuditLogs, User } from "discord.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an UNBAN case automatically when a user is unbanned manually.
|
* Create an UNBAN case automatically when a user is unbanned manually.
|
||||||
|
@ -15,7 +16,8 @@ import { Case } from "../../../data/entities/Case";
|
||||||
*/
|
*/
|
||||||
export const CreateUnbanCaseOnManualUnbanEvt = modActionsEvt({
|
export const CreateUnbanCaseOnManualUnbanEvt = modActionsEvt({
|
||||||
event: "guildBanRemove",
|
event: "guildBanRemove",
|
||||||
async listener({ pluginData, args: { guild, user } }) {
|
async listener({ pluginData, args: { ban } }) {
|
||||||
|
const user = ban.user;
|
||||||
if (isEventIgnored(pluginData, IgnoredEventType.Unban, user.id)) {
|
if (isEventIgnored(pluginData, IgnoredEventType.Unban, user.id)) {
|
||||||
clearIgnoredEvents(pluginData, IgnoredEventType.Unban, user.id);
|
clearIgnoredEvents(pluginData, IgnoredEventType.Unban, user.id);
|
||||||
return;
|
return;
|
||||||
|
@ -23,7 +25,7 @@ export const CreateUnbanCaseOnManualUnbanEvt = modActionsEvt({
|
||||||
|
|
||||||
const relevantAuditLogEntry = await safeFindRelevantAuditLogEntry(
|
const relevantAuditLogEntry = await safeFindRelevantAuditLogEntry(
|
||||||
pluginData,
|
pluginData,
|
||||||
ErisConstants.AuditLogActions.MEMBER_BAN_REMOVE,
|
GuildAuditLogs.Actions.MEMBER_BAN_REMOVE as number,
|
||||||
user.id,
|
user.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -33,7 +35,7 @@ export const CreateUnbanCaseOnManualUnbanEvt = modActionsEvt({
|
||||||
let mod: User | UnknownUser | null = null;
|
let mod: User | UnknownUser | null = null;
|
||||||
|
|
||||||
if (relevantAuditLogEntry) {
|
if (relevantAuditLogEntry) {
|
||||||
const modId = relevantAuditLogEntry.user.id;
|
const modId = relevantAuditLogEntry.executor!.id;
|
||||||
const auditLogId = relevantAuditLogEntry.id;
|
const auditLogId = relevantAuditLogEntry.id;
|
||||||
|
|
||||||
mod = await resolveUser(pluginData.client, modId);
|
mod = await resolveUser(pluginData.client, modId);
|
||||||
|
|
|
@ -4,13 +4,14 @@ import { LogType } from "../../../data/LogType";
|
||||||
|
|
||||||
import { resolveMember } from "../../../utils";
|
import { resolveMember } from "../../../utils";
|
||||||
import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions";
|
import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions";
|
||||||
|
import { TextChannel, Constants, Permissions } from "discord.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show an alert if a member with prior notes joins the server
|
* Show an alert if a member with prior notes joins the server
|
||||||
*/
|
*/
|
||||||
export const PostAlertOnMemberJoinEvt = modActionsEvt({
|
export const PostAlertOnMemberJoinEvt = modActionsEvt({
|
||||||
event: "guildMemberAdd",
|
event: "guildMemberAdd",
|
||||||
async listener({ pluginData, args: { guild, member } }) {
|
async listener({ pluginData, args: { member } }) {
|
||||||
const config = pluginData.config.get();
|
const config = pluginData.config.get();
|
||||||
|
|
||||||
if (!config.alert_on_rejoin) return;
|
if (!config.alert_on_rejoin) return;
|
||||||
|
@ -38,15 +39,15 @@ export const PostAlertOnMemberJoinEvt = modActionsEvt({
|
||||||
}
|
}
|
||||||
|
|
||||||
const botMember = await resolveMember(pluginData.client, pluginData.guild, pluginData.client.user!.id);
|
const botMember = await resolveMember(pluginData.client, pluginData.guild, pluginData.client.user!.id);
|
||||||
const botPerms = alertChannel.permissionsOf(botMember ?? pluginData.client.user!.id);
|
const botPerms = alertChannel.permissionsFor(botMember ?? pluginData.client.user!.id);
|
||||||
if (!hasDiscordPermissions(botPerms, Constants.Permissions.sendMessages)) {
|
if (!hasDiscordPermissions(botPerms, Permissions.FLAGS.SEND_MESSAGES)) {
|
||||||
logs.log(LogType.BOT_ALERT, {
|
logs.log(LogType.BOT_ALERT, {
|
||||||
body: `Missing "Send Messages" permissions for the \`alert_channel\` configured in \`mod_actions\`: \`${alertChannelId}\``,
|
body: `Missing "Send Messages" permissions for the \`alert_channel\` configured in \`mod_actions\`: \`${alertChannelId}\``,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await alertChannel.createMessage(
|
await alertChannel.send(
|
||||||
`<@!${member.id}> (${member.user.username}#${member.user.discriminator} \`${member.id}\`) joined with ${actions.length} prior record(s)`,
|
`<@!${member.id}> (${member.user.username}#${member.user.discriminator} \`${member.id}\`) joined with ${actions.length} prior record(s)`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { formatReasonWithAttachments } from "./formatReasonWithAttachments";
|
||||||
import { kickMember } from "./kickMember";
|
import { kickMember } from "./kickMember";
|
||||||
import { ignoreEvent } from "./ignoreEvent";
|
import { ignoreEvent } from "./ignoreEvent";
|
||||||
import { isBanned } from "./isBanned";
|
import { isBanned } from "./isBanned";
|
||||||
|
import { GuildMember, TextChannel } from "discord.js";
|
||||||
|
|
||||||
export async function actualKickMemberCmd(
|
export async function actualKickMemberCmd(
|
||||||
pluginData: GuildPluginData<ModActionsPluginType>,
|
pluginData: GuildPluginData<ModActionsPluginType>,
|
||||||
|
@ -16,7 +17,7 @@ export async function actualKickMemberCmd(
|
||||||
args: {
|
args: {
|
||||||
user: string;
|
user: string;
|
||||||
reason: string;
|
reason: string;
|
||||||
mod: Member;
|
mod: GuildMember;
|
||||||
notify?: string;
|
notify?: string;
|
||||||
"notify-channel"?: TextChannel;
|
"notify-channel"?: TextChannel;
|
||||||
clean?: boolean;
|
clean?: boolean;
|
||||||
|
@ -81,7 +82,7 @@ export async function actualKickMemberCmd(
|
||||||
ignoreEvent(pluginData, IgnoredEventType.Ban, memberToKick.id);
|
ignoreEvent(pluginData, IgnoredEventType.Ban, memberToKick.id);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await memberToKick.ban(1, encodeURIComponent("kick -clean"));
|
await memberToKick.ban({ days: 1, reason: encodeURIComponent("kick -clean") });
|
||||||
} catch {
|
} catch {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Failed to ban the user to clean messages (-clean)");
|
sendErrorMessage(pluginData, msg.channel, "Failed to ban the user to clean messages (-clean)");
|
||||||
}
|
}
|
||||||
|
@ -90,14 +91,14 @@ export async function actualKickMemberCmd(
|
||||||
ignoreEvent(pluginData, IgnoredEventType.Unban, memberToKick.id);
|
ignoreEvent(pluginData, IgnoredEventType.Unban, memberToKick.id);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await pluginData.guild.unbanMember(memberToKick.id, encodeURIComponent("kick -clean"));
|
await pluginData.guild.bans.remove(memberToKick.id, encodeURIComponent("kick -clean"));
|
||||||
} catch {
|
} catch {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Failed to unban the user after banning them (-clean)");
|
sendErrorMessage(pluginData, msg.channel, "Failed to unban the user after banning them (-clean)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kickResult.status === "failed") {
|
if (kickResult.status === "failed") {
|
||||||
msg.channel.createMessage(errorMessage(`Failed to kick user`));
|
msg.channel.send(errorMessage(`Failed to kick user`));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { MutesPlugin } from "../../Mutes/MutesPlugin";
|
||||||
import { readContactMethodsFromArgs } from "./readContactMethodsFromArgs";
|
import { readContactMethodsFromArgs } from "./readContactMethodsFromArgs";
|
||||||
import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError";
|
import { ERRORS, RecoverablePluginError } from "../../../RecoverablePluginError";
|
||||||
import { logger } from "../../../logger";
|
import { logger } from "../../../logger";
|
||||||
|
import { User, Message, TextChannel, GuildMember } from "discord.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The actual function run by both !mute and !forcemute.
|
* The actual function run by both !mute and !forcemute.
|
||||||
|
@ -17,16 +18,16 @@ import { logger } from "../../../logger";
|
||||||
export async function actualMuteUserCmd(
|
export async function actualMuteUserCmd(
|
||||||
pluginData: GuildPluginData<ModActionsPluginType>,
|
pluginData: GuildPluginData<ModActionsPluginType>,
|
||||||
user: User | UnknownUser,
|
user: User | UnknownUser,
|
||||||
msg: Message<GuildTextableChannel>,
|
msg: Message,
|
||||||
args: { time?: number; reason?: string; mod: Member; notify?: string; "notify-channel"?: TextChannel },
|
args: { time?: number; reason?: string; mod: GuildMember; notify?: string; "notify-channel"?: TextChannel },
|
||||||
) {
|
) {
|
||||||
// The moderator who did the action is the message author or, if used, the specified -mod
|
// The moderator who did the action is the message author or, if used, the specified -mod
|
||||||
let mod: Member = msg.member;
|
let mod: GuildMember = msg.member!;
|
||||||
let pp: User | null = null;
|
let pp: User | null = null;
|
||||||
|
|
||||||
if (args.mod) {
|
if (args.mod) {
|
||||||
if (!(await hasPermission(pluginData, "can_act_as_other", { message: msg }))) {
|
if (!(await hasPermission(pluginData, "can_act_as_other", { message: msg }))) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "You don't have permission to use -mod");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "You don't have permission to use -mod");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +36,7 @@ export async function actualMuteUserCmd(
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeUntilUnmute = args.time && humanizeDuration(args.time);
|
const timeUntilUnmute = args.time && humanizeDuration(args.time);
|
||||||
const reason = args.reason ? formatReasonWithAttachments(args.reason, msg.attachments) : undefined;
|
const reason = args.reason ? formatReasonWithAttachments(args.reason, msg.attachments.array()) : undefined;
|
||||||
|
|
||||||
let muteResult: MuteResult;
|
let muteResult: MuteResult;
|
||||||
const mutesPlugin = pluginData.getPlugin(MutesPlugin);
|
const mutesPlugin = pluginData.getPlugin(MutesPlugin);
|
||||||
|
@ -44,7 +45,7 @@ export async function actualMuteUserCmd(
|
||||||
try {
|
try {
|
||||||
contactMethods = readContactMethodsFromArgs(args);
|
contactMethods = readContactMethodsFromArgs(args);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
sendErrorMessage(pluginData, msg.channel, e.message);
|
sendErrorMessage(pluginData, msg.channel as TextChannel, e.message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,16 +59,16 @@ export async function actualMuteUserCmd(
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof RecoverablePluginError && e.code === ERRORS.NO_MUTE_ROLE_IN_CONFIG) {
|
if (e instanceof RecoverablePluginError && e.code === ERRORS.NO_MUTE_ROLE_IN_CONFIG) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Could not mute the user: no mute role set in config");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "Could not mute the user: no mute role set in config");
|
||||||
} else if (isDiscordRESTError(e) && e.code === 10007) {
|
} else if (isDiscordRESTError(e) && e.code === 10007) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Could not mute the user: unknown member");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "Could not mute the user: unknown member");
|
||||||
} else {
|
} else {
|
||||||
logger.error(`Failed to mute user ${user.id}: ${e.stack}`);
|
logger.error(`Failed to mute user ${user.id}: ${e.stack}`);
|
||||||
if (user.id == null) {
|
if (user.id == null) {
|
||||||
// tslint-disable-next-line:no-console
|
// tslint-disable-next-line:no-console
|
||||||
console.trace("[DEBUG] Null user.id for mute");
|
console.trace("[DEBUG] Null user.id for mute");
|
||||||
}
|
}
|
||||||
sendErrorMessage(pluginData, msg.channel, "Could not mute the user");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "Could not mute the user");
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -102,5 +103,5 @@ export async function actualMuteUserCmd(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (muteResult.notifyResult.text) response += ` (${muteResult.notifyResult.text})`;
|
if (muteResult.notifyResult.text) response += ` (${muteResult.notifyResult.text})`;
|
||||||
sendSuccessMessage(pluginData, msg.channel, response);
|
sendSuccessMessage(pluginData, msg.channel as TextChannel, response);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,13 @@ import { sendErrorMessage, sendSuccessMessage, hasPermission } from "../../../pl
|
||||||
import { formatReasonWithAttachments } from "./formatReasonWithAttachments";
|
import { formatReasonWithAttachments } from "./formatReasonWithAttachments";
|
||||||
import { MutesPlugin } from "../../../plugins/Mutes/MutesPlugin";
|
import { MutesPlugin } from "../../../plugins/Mutes/MutesPlugin";
|
||||||
import humanizeDuration from "humanize-duration";
|
import humanizeDuration from "humanize-duration";
|
||||||
|
import { User, Message, GuildMember, TextChannel } from "discord.js";
|
||||||
|
|
||||||
export async function actualUnmuteCmd(
|
export async function actualUnmuteCmd(
|
||||||
pluginData: GuildPluginData<ModActionsPluginType>,
|
pluginData: GuildPluginData<ModActionsPluginType>,
|
||||||
user: User | UnknownUser,
|
user: User | UnknownUser,
|
||||||
msg: Message,
|
msg: Message,
|
||||||
args: { time?: number; reason?: string; mod?: Member },
|
args: { time?: number; reason?: string; mod?: GuildMember },
|
||||||
) {
|
) {
|
||||||
// The moderator who did the action is the message author or, if used, the specified -mod
|
// The moderator who did the action is the message author or, if used, the specified -mod
|
||||||
let mod = msg.author;
|
let mod = msg.author;
|
||||||
|
@ -19,7 +20,7 @@ export async function actualUnmuteCmd(
|
||||||
|
|
||||||
if (args.mod) {
|
if (args.mod) {
|
||||||
if (!(await hasPermission(pluginData, "can_act_as_other", { message: msg, channelId: msg.channel.id }))) {
|
if (!(await hasPermission(pluginData, "can_act_as_other", { message: msg, channelId: msg.channel.id }))) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "You don't have permission to use -mod");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "You don't have permission to use -mod");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +28,7 @@ export async function actualUnmuteCmd(
|
||||||
pp = msg.author;
|
pp = msg.author;
|
||||||
}
|
}
|
||||||
|
|
||||||
const reason = args.reason ? formatReasonWithAttachments(args.reason, msg.attachments) : undefined;
|
const reason = args.reason ? formatReasonWithAttachments(args.reason, msg.attachments.array()) : undefined;
|
||||||
|
|
||||||
const mutesPlugin = pluginData.getPlugin(MutesPlugin);
|
const mutesPlugin = pluginData.getPlugin(MutesPlugin);
|
||||||
const result = await mutesPlugin.unmuteUser(user.id, args.time, {
|
const result = await mutesPlugin.unmuteUser(user.id, args.time, {
|
||||||
|
@ -37,7 +38,7 @@ export async function actualUnmuteCmd(
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "User is not muted!");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "User is not muted!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +47,7 @@ export async function actualUnmuteCmd(
|
||||||
const timeUntilUnmute = args.time && humanizeDuration(args.time);
|
const timeUntilUnmute = args.time && humanizeDuration(args.time);
|
||||||
sendSuccessMessage(
|
sendSuccessMessage(
|
||||||
pluginData,
|
pluginData,
|
||||||
msg.channel,
|
msg.channel as TextChannel,
|
||||||
asSingleLine(`
|
asSingleLine(`
|
||||||
Unmuting **${user.username}#${user.discriminator}**
|
Unmuting **${user.username}#${user.discriminator}**
|
||||||
in ${timeUntilUnmute} (Case #${result.case.case_number})
|
in ${timeUntilUnmute} (Case #${result.case.case_number})
|
||||||
|
@ -55,7 +56,7 @@ export async function actualUnmuteCmd(
|
||||||
} else {
|
} else {
|
||||||
sendSuccessMessage(
|
sendSuccessMessage(
|
||||||
pluginData,
|
pluginData,
|
||||||
msg.channel,
|
msg.channel as TextChannel,
|
||||||
asSingleLine(`
|
asSingleLine(`
|
||||||
Unmuted **${user.username}#${user.discriminator}**
|
Unmuted **${user.username}#${user.discriminator}**
|
||||||
(Case #${result.case.case_number})
|
(Case #${result.case.case_number})
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { CasesPlugin } from "../../Cases/CasesPlugin";
|
||||||
import { CaseTypes } from "../../../data/CaseTypes";
|
import { CaseTypes } from "../../../data/CaseTypes";
|
||||||
import { logger } from "../../../logger";
|
import { logger } from "../../../logger";
|
||||||
import humanizeDuration from "humanize-duration";
|
import humanizeDuration from "humanize-duration";
|
||||||
|
import { DiscordAPIError, User } from "discord.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ban the specified user id, whether or not they're actually on the server at the time. Generates a case.
|
* Ban the specified user id, whether or not they're actually on the server at the time. Generates a case.
|
||||||
|
@ -77,14 +78,13 @@ export async function banUserId(
|
||||||
ignoreEvent(pluginData, IgnoredEventType.Ban, userId);
|
ignoreEvent(pluginData, IgnoredEventType.Ban, userId);
|
||||||
try {
|
try {
|
||||||
const deleteMessageDays = Math.min(30, Math.max(0, banOptions.deleteMessageDays ?? 1));
|
const deleteMessageDays = Math.min(30, Math.max(0, banOptions.deleteMessageDays ?? 1));
|
||||||
await pluginData.guild.banMember(
|
await pluginData.guild.bans.create(userId, {
|
||||||
userId,
|
days: deleteMessageDays,
|
||||||
deleteMessageDays,
|
reason: reason != null ? encodeURIComponent(reason) : undefined,
|
||||||
reason != null ? encodeURIComponent(reason) : undefined,
|
});
|
||||||
);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
let errorMessage;
|
let errorMessage;
|
||||||
if (e instanceof DiscordRESTError) {
|
if (e instanceof DiscordAPIError) {
|
||||||
errorMessage = `API error ${e.code}: ${e.message}`;
|
errorMessage = `API error ${e.code}: ${e.message}`;
|
||||||
} else {
|
} else {
|
||||||
logger.warn(`Error applying ban to ${userId}: ${e}`);
|
logger.warn(`Error applying ban to ${userId}: ${e}`);
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
export function formatReasonWithAttachments(reason: string, attachments: Attachment[]) {
|
import { MessageAttachment } from "discord.js";
|
||||||
|
|
||||||
|
export function formatReasonWithAttachments(reason: string, attachments: MessageAttachment[]) {
|
||||||
const attachmentUrls = attachments.map(a => a.url);
|
const attachmentUrls = attachments.map(a => a.url);
|
||||||
return ((reason || "") + " " + attachmentUrls.join(" ")).trim();
|
return ((reason || "") + " " + attachmentUrls.join(" ")).trim();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { GuildPluginData } from "knub";
|
import { GuildPluginData } from "knub";
|
||||||
import { ModActionsPluginType } from "../types";
|
import { ModActionsPluginType } from "../types";
|
||||||
import { UserNotificationMethod } from "../../../utils";
|
import { UserNotificationMethod } from "../../../utils";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export function getDefaultContactMethods(
|
export function getDefaultContactMethods(
|
||||||
pluginData: GuildPluginData<ModActionsPluginType>,
|
pluginData: GuildPluginData<ModActionsPluginType>,
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { isDiscordHTTPError, isDiscordRESTError, SECONDS, sleep } from "../../..
|
||||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions";
|
import { hasDiscordPermissions } from "../../../utils/hasDiscordPermissions";
|
||||||
|
import { Permissions } from "discord.js";
|
||||||
|
|
||||||
export async function isBanned(
|
export async function isBanned(
|
||||||
pluginData: GuildPluginData<ModActionsPluginType>,
|
pluginData: GuildPluginData<ModActionsPluginType>,
|
||||||
|
@ -11,7 +12,7 @@ export async function isBanned(
|
||||||
timeout: number = 5 * SECONDS,
|
timeout: number = 5 * SECONDS,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const botMember = pluginData.guild.members.cache.get(pluginData.client.user!.id);
|
const botMember = pluginData.guild.members.cache.get(pluginData.client.user!.id);
|
||||||
if (botMember && !hasDiscordPermissions(botMember.permissions, Constants.Permissions.banMembers)) {
|
if (botMember && !hasDiscordPermissions(botMember.permissions, Permissions.FLAGS.BAN_MEMBERS)) {
|
||||||
pluginData.getPlugin(LogsPlugin).log(LogType.BOT_ALERT, {
|
pluginData.getPlugin(LogsPlugin).log(LogType.BOT_ALERT, {
|
||||||
body: `Missing "Ban Members" permission to check for existing bans`,
|
body: `Missing "Ban Members" permission to check for existing bans`,
|
||||||
});
|
});
|
||||||
|
@ -19,7 +20,7 @@ export async function isBanned(
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const potentialBan = await Promise.race([pluginData.guild.getBan(userId), sleep(timeout)]);
|
const potentialBan = await Promise.race([pluginData.guild.bans.fetch({ user: userId }), sleep(timeout)]);
|
||||||
return potentialBan != null;
|
return potentialBan != null;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (isDiscordRESTError(e) && e.code === 10026) {
|
if (isDiscordRESTError(e) && e.code === 10026) {
|
||||||
|
|
|
@ -15,13 +15,14 @@ import { LogType } from "../../../data/LogType";
|
||||||
import { ignoreEvent } from "./ignoreEvent";
|
import { ignoreEvent } from "./ignoreEvent";
|
||||||
import { CaseTypes } from "../../../data/CaseTypes";
|
import { CaseTypes } from "../../../data/CaseTypes";
|
||||||
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
||||||
|
import { GuildMember } from "discord.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kick the specified server member. Generates a case.
|
* Kick the specified server member. Generates a case.
|
||||||
*/
|
*/
|
||||||
export async function kickMember(
|
export async function kickMember(
|
||||||
pluginData: GuildPluginData<ModActionsPluginType>,
|
pluginData: GuildPluginData<ModActionsPluginType>,
|
||||||
member: Member,
|
member: GuildMember,
|
||||||
reason?: string,
|
reason?: string,
|
||||||
kickOptions: KickOptions = {},
|
kickOptions: KickOptions = {},
|
||||||
): Promise<KickResult> {
|
): Promise<KickResult> {
|
||||||
|
|
|
@ -30,7 +30,7 @@ export async function outdatedTempbansLoop(pluginData: GuildPluginData<ModAction
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
ignoreEvent(pluginData, IgnoredEventType.Unban, tempban.user_id);
|
ignoreEvent(pluginData, IgnoredEventType.Unban, tempban.user_id);
|
||||||
await pluginData.guild.unbanMember(tempban.user_id, reason != null ? encodeURIComponent(reason) : undefined);
|
await pluginData.guild.bans.remove(tempban.user_id, reason != null ? encodeURIComponent(reason) : undefined);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
pluginData.state.serverLogs.log(LogType.BOT_ALERT, {
|
pluginData.state.serverLogs.log(LogType.BOT_ALERT, {
|
||||||
body: `Encountered an error trying to automatically unban ${tempban.user_id} after tempban timeout`,
|
body: `Encountered an error trying to automatically unban ${tempban.user_id} after tempban timeout`,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
import { disableUserNotificationStrings, UserNotificationMethod } from "../../../utils";
|
import { disableUserNotificationStrings, UserNotificationMethod } from "../../../utils";
|
||||||
|
|
||||||
export function readContactMethodsFromArgs(args: {
|
export function readContactMethodsFromArgs(args: {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { Message, TextChannel } from "discord.js";
|
||||||
import { CaseTypes } from "../../../data/CaseTypes";
|
import { CaseTypes } from "../../../data/CaseTypes";
|
||||||
import { Case } from "../../../data/entities/Case";
|
import { Case } from "../../../data/entities/Case";
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
|
@ -14,16 +15,16 @@ export async function updateCase(pluginData, msg: Message, args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!theCase) {
|
if (!theCase) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Case not found");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "Case not found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!args.note && msg.attachments.length === 0) {
|
if (!args.note && msg.attachments.size === 0) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Text or attachment required");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "Text or attachment required");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const note = formatReasonWithAttachments(args.note, msg.attachments);
|
const note = formatReasonWithAttachments(args.note, msg.attachments.array());
|
||||||
|
|
||||||
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
const casesPlugin = pluginData.getPlugin(CasesPlugin);
|
||||||
await casesPlugin.createCaseNote({
|
await casesPlugin.createCaseNote({
|
||||||
|
@ -39,5 +40,5 @@ export async function updateCase(pluginData, msg: Message, args) {
|
||||||
note,
|
note,
|
||||||
});
|
});
|
||||||
|
|
||||||
sendSuccessMessage(pluginData, msg.channel, `Case \`#${theCase.case_number}\` updated`);
|
sendSuccessMessage(pluginData, msg.channel as TextChannel, `Case \`#${theCase.case_number}\` updated`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,15 +10,15 @@ import {
|
||||||
ucfirst,
|
ucfirst,
|
||||||
UserNotificationResult,
|
UserNotificationResult,
|
||||||
} from "../../../utils";
|
} from "../../../utils";
|
||||||
import { waitForReaction } from "knub/dist/helpers";
|
|
||||||
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
import { CasesPlugin } from "../../Cases/CasesPlugin";
|
||||||
import { CaseTypes } from "../../../data/CaseTypes";
|
import { CaseTypes } from "../../../data/CaseTypes";
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
import { renderTemplate } from "../../../templateFormatter";
|
import { renderTemplate } from "../../../templateFormatter";
|
||||||
|
import { GuildMember } from "discord.js";
|
||||||
|
|
||||||
export async function warnMember(
|
export async function warnMember(
|
||||||
pluginData: GuildPluginData<ModActionsPluginType>,
|
pluginData: GuildPluginData<ModActionsPluginType>,
|
||||||
member: Member,
|
member: GuildMember,
|
||||||
reason: string,
|
reason: string,
|
||||||
warnOptions: WarnOptions = {},
|
warnOptions: WarnOptions = {},
|
||||||
): Promise<WarnResult> {
|
): Promise<WarnResult> {
|
||||||
|
@ -42,13 +42,13 @@ export async function warnMember(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!notifyResult.success) {
|
if (!notifyResult.success) {
|
||||||
if (warnOptions.retryPromptChannel && pluginData.guild.channels.has(warnOptions.retryPromptChannel.id)) {
|
if (warnOptions.retryPromptChannel && pluginData.guild.channels.resolve(warnOptions.retryPromptChannel.id)) {
|
||||||
const failedMsg = await warnOptions.retryPromptChannel.createMessage(
|
const failedMsg = await warnOptions.retryPromptChannel.send(
|
||||||
"Failed to message the user. Log the warning anyway?",
|
"Failed to message the user. Log the warning anyway?",
|
||||||
);
|
);
|
||||||
const reply = await waitForReaction(pluginData.client, failedMsg, ["✅", "❌"]);
|
const reply = false; //await waitForReaction(pluginData.client, failedMsg, ["✅", "❌"]); FIXME waiting on waitForButton
|
||||||
failedMsg.delete();
|
failedMsg.delete();
|
||||||
if (!reply || reply.name === "❌") {
|
if (!reply /*|| reply.name === "❌"*/) {
|
||||||
return {
|
return {
|
||||||
status: "failed",
|
status: "failed",
|
||||||
error: "Failed to message user",
|
error: "Failed to message user",
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { GuildTempbans } from "../../data/GuildTempbans";
|
||||||
import Timeout = NodeJS.Timeout;
|
import Timeout = NodeJS.Timeout;
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
import { Queue } from "../../Queue";
|
import { Queue } from "../../Queue";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
export const ConfigSchema = t.type({
|
||||||
dm_on_warn: t.boolean,
|
dm_on_warn: t.boolean,
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { mapToPublicFn } from "../../pluginUtils";
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
import { onMutesEvent } from "./functions/onMutesEvent";
|
import { onMutesEvent } from "./functions/onMutesEvent";
|
||||||
import { offMutesEvent } from "./functions/offMutesEvent";
|
import { offMutesEvent } from "./functions/offMutesEvent";
|
||||||
|
import { GuildMember } from "discord.js";
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
config: {
|
config: {
|
||||||
|
@ -92,9 +93,9 @@ export const MutesPlugin = zeppelinGuildPlugin<MutesPluginType>()({
|
||||||
muteUser: mapToPublicFn(muteUser),
|
muteUser: mapToPublicFn(muteUser),
|
||||||
unmuteUser: mapToPublicFn(unmuteUser),
|
unmuteUser: mapToPublicFn(unmuteUser),
|
||||||
hasMutedRole(pluginData) {
|
hasMutedRole(pluginData) {
|
||||||
return (member: Member) => {
|
return (member: GuildMember) => {
|
||||||
const muteRole = pluginData.config.get().mute_role;
|
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 { mutesCmd } from "../types";
|
||||||
|
|
||||||
import { sendSuccessMessage } from "../../../pluginUtils";
|
import { sendSuccessMessage } from "../../../pluginUtils";
|
||||||
|
import { User } from "discord.js";
|
||||||
|
|
||||||
export const ClearBannedMutesCmd = mutesCmd({
|
export const ClearBannedMutesCmd = mutesCmd({
|
||||||
trigger: "clear_banned_mutes",
|
trigger: "clear_banned_mutes",
|
||||||
|
@ -8,17 +9,14 @@ export const ClearBannedMutesCmd = mutesCmd({
|
||||||
description: "Clear dangling mutes for members who have been banned",
|
description: "Clear dangling mutes for members who have been banned",
|
||||||
|
|
||||||
async run({ pluginData, message: msg }) {
|
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();
|
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.bans.fetch({ cache: true })) as any;
|
||||||
const bans: Array<{ reason: string; user: User }> = (await pluginData.guild.getBans()) as any;
|
|
||||||
const bannedIds = bans.map(b => b.user.id);
|
const bannedIds = bans.map(b => b.user.id);
|
||||||
|
|
||||||
await msg.channel.createMessage(
|
await msg.channel.send(`Found ${activeMutes.length} mutes and ${bannedIds.length} bans, cross-referencing...`);
|
||||||
`Found ${activeMutes.length} mutes and ${bannedIds.length} bans, cross-referencing...`,
|
|
||||||
);
|
|
||||||
|
|
||||||
let cleared = 0;
|
let cleared = 0;
|
||||||
for (const mute of activeMutes) {
|
for (const mute of activeMutes) {
|
||||||
|
|
|
@ -12,14 +12,14 @@ export const ClearMutesWithoutRoleCmd = mutesCmd({
|
||||||
const muteRole = pluginData.config.get().mute_role;
|
const muteRole = pluginData.config.get().mute_role;
|
||||||
if (!muteRole) return;
|
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;
|
let cleared = 0;
|
||||||
for (const mute of activeMutes) {
|
for (const mute of activeMutes) {
|
||||||
const member = await resolveMember(pluginData.client, pluginData.guild, mute.user_id);
|
const member = await resolveMember(pluginData.client, pluginData.guild, mute.user_id);
|
||||||
if (!member) continue;
|
if (!member) continue;
|
||||||
|
|
||||||
if (!member.roles.includes(muteRole)) {
|
if (!member.roles.cache.has(muteRole)) {
|
||||||
await pluginData.state.mutes.clear(mute.user_id);
|
await pluginData.state.mutes.clear(mute.user_id);
|
||||||
cleared++;
|
cleared++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { DBDateFormat, isFullMessage, MINUTES, noop, resolveMember } from "../..
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import { humanizeDurationShort } from "../../../humanizeDurationShort";
|
import { humanizeDurationShort } from "../../../humanizeDurationShort";
|
||||||
import { getBaseUrl } from "../../../pluginUtils";
|
import { getBaseUrl } from "../../../pluginUtils";
|
||||||
|
import { GuildMember } from "discord.js";
|
||||||
|
|
||||||
export const MutesCmd = mutesCmd({
|
export const MutesCmd = mutesCmd({
|
||||||
trigger: "mutes",
|
trigger: "mutes",
|
||||||
|
@ -21,7 +22,7 @@ export const MutesCmd = mutesCmd({
|
||||||
},
|
},
|
||||||
|
|
||||||
async run({ pluginData, message: msg, args }) {
|
async run({ pluginData, message: msg, args }) {
|
||||||
const listMessagePromise = msg.channel.createMessage("Loading mutes...");
|
const listMessagePromise = msg.channel.send("Loading mutes...");
|
||||||
const mutesPerPage = 10;
|
const mutesPerPage = 10;
|
||||||
let totalMutes = 0;
|
let totalMutes = 0;
|
||||||
let hasFilters = false;
|
let hasFilters = false;
|
||||||
|
@ -47,13 +48,13 @@ export const MutesCmd = mutesCmd({
|
||||||
if (args.manual) {
|
if (args.manual) {
|
||||||
// Show only manual mutes (i.e. "Muted" role added without a logged mute)
|
// Show only manual mutes (i.e. "Muted" role added without a logged mute)
|
||||||
const muteUserIds = new Set(activeMutes.map(m => m.user_id));
|
const muteUserIds = new Set(activeMutes.map(m => m.user_id));
|
||||||
const manuallyMutedMembers: Member[] = [];
|
const manuallyMutedMembers: GuildMember[] = [];
|
||||||
const muteRole = pluginData.config.get().mute_role;
|
const muteRole = pluginData.config.get().mute_role;
|
||||||
|
|
||||||
if (muteRole) {
|
if (muteRole) {
|
||||||
pluginData.guild.members.forEach(member => {
|
pluginData.guild.members.cache.forEach(member => {
|
||||||
if (muteUserIds.has(member.id)) return;
|
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 (!member) {
|
||||||
if (!bannedIds) {
|
if (!bannedIds) {
|
||||||
const bans = await pluginData.guild.getBans();
|
const bans = await pluginData.guild.bans.fetch({ cache: true });
|
||||||
bannedIds = bans.map(u => u.user.id);
|
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());
|
const muteCasesById = muteCases.reduce((map, c) => map.set(c.id, c), new Map());
|
||||||
|
|
||||||
lines = filteredMutes.map(mute => {
|
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 username = user ? `${user.username}#${user.discriminator}` : "Unknown#0000";
|
||||||
const theCase = muteCasesById.get(mute.case_id);
|
const theCase = muteCasesById.get(mute.case_id);
|
||||||
const caseName = theCase ? `Case #${theCase.case_number}` : "No case";
|
const caseName = theCase ? `Case #${theCase.case_number}` : "No case";
|
||||||
|
@ -194,29 +195,31 @@ export const MutesCmd = mutesCmd({
|
||||||
|
|
||||||
if (totalPages > 1) {
|
if (totalPages > 1) {
|
||||||
hasReactions = true;
|
hasReactions = true;
|
||||||
listMessage.addReaction("⬅");
|
listMessage.react("⬅");
|
||||||
listMessage.addReaction("➡");
|
listMessage.react("➡");
|
||||||
|
|
||||||
const paginationReactionListener = pluginData.events.on(
|
const paginationReactionListener = pluginData.events.on(
|
||||||
"messageReactionAdd",
|
"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 (!isFullMessage(rMsg)) return;
|
||||||
if (rMsg.id !== listMessage.id) return;
|
if (rMsg.id !== listMessage.id) return;
|
||||||
if (member.id !== msg.author.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);
|
drawListPage(currentPage - 1);
|
||||||
} else if (emoji.name === "➡" && currentPage < totalPages) {
|
} else if (reaction.emoji.name === "➡" && currentPage < totalPages) {
|
||||||
drawListPage(currentPage + 1);
|
drawListPage(currentPage + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
rMsg.removeReaction(emoji.name, member.id).catch(noop);
|
reaction.remove().catch(noop);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
clearReactionsFn = () => {
|
clearReactionsFn = () => {
|
||||||
listMessage.removeReactions().catch(noop);
|
listMessage.reactions.removeAll().catch(noop);
|
||||||
pluginData.events.off("messageReactionAdd", paginationReactionListener);
|
pluginData.events.off("messageReactionAdd", paginationReactionListener);
|
||||||
};
|
};
|
||||||
bumpClearReactionsTimeout();
|
bumpClearReactionsTimeout();
|
||||||
|
|
|
@ -5,10 +5,10 @@ import { mutesEvt } from "../types";
|
||||||
*/
|
*/
|
||||||
export const ClearActiveMuteOnMemberBanEvt = mutesEvt({
|
export const ClearActiveMuteOnMemberBanEvt = mutesEvt({
|
||||||
event: "guildBanAdd",
|
event: "guildBanAdd",
|
||||||
async listener({ pluginData, args: { user } }) {
|
async listener({ pluginData, args: { ban } }) {
|
||||||
const mute = await pluginData.state.mutes.findExistingMuteForUserId(user.id);
|
const mute = await pluginData.state.mutes.findExistingMuteForUserId(ban.user.id);
|
||||||
if (mute) {
|
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({
|
export const ClearActiveMuteOnRoleRemovalEvt = mutesEvt({
|
||||||
event: "guildMemberUpdate",
|
event: "guildMemberUpdate",
|
||||||
async listener({ pluginData, args: { member } }) {
|
async listener({ pluginData, args: { oldMember, newMember: member } }) {
|
||||||
const muteRole = pluginData.config.get().mute_role;
|
const muteRole = pluginData.config.get().mute_role;
|
||||||
if (!muteRole) return;
|
if (!muteRole) return;
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ export const ReapplyActiveMuteOnJoinEvt = mutesEvt({
|
||||||
|
|
||||||
if (muteRole) {
|
if (muteRole) {
|
||||||
const memberRoleLock = await pluginData.locks.acquire(memberRolesLock(member));
|
const memberRoleLock = await pluginData.locks.acquire(memberRolesLock(member));
|
||||||
await member.addRole(muteRole);
|
await member.roles.add(muteRole);
|
||||||
memberRoleLock.unlock();
|
memberRoleLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,17 +16,17 @@ export async function clearExpiredMutes(pluginData: GuildPluginData<MutesPluginT
|
||||||
|
|
||||||
const muteRole = pluginData.config.get().mute_role;
|
const muteRole = pluginData.config.get().mute_role;
|
||||||
if (muteRole) {
|
if (muteRole) {
|
||||||
await member.removeRole(muteRole);
|
await member.roles.remove(muteRole);
|
||||||
member.roles = member.roles.filter(r => r !== muteRole);
|
|
||||||
}
|
}
|
||||||
if (mute.roles_to_restore) {
|
if (mute.roles_to_restore) {
|
||||||
const memberOptions: MemberOptions = {};
|
const guildRoles = pluginData.guild.roles.cache;
|
||||||
const guildRoles = pluginData.guild.roles;
|
let newRoles: string[] = member.roles.cache.keyArray();
|
||||||
memberOptions.roles = Array.from(
|
newRoles =
|
||||||
new Set([...mute.roles_to_restore, ...member.roles.filter(x => x !== muteRole && guildRoles.has(x))]),
|
muteRole && newRoles.includes(muteRole) ? newRoles.splice(newRoles.indexOf(muteRole), 1) : newRoles;
|
||||||
);
|
for (const toRestore of mute.roles_to_restore) {
|
||||||
await member.edit(memberOptions);
|
if (guildRoles.has(toRestore) && toRestore !== muteRole) newRoles.push(toRestore);
|
||||||
member.roles = memberOptions.roles;
|
}
|
||||||
|
await member.roles.set(newRoles);
|
||||||
}
|
}
|
||||||
|
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
import { GuildMember } from "discord.js";
|
||||||
import { GuildPluginData } from "knub";
|
import { GuildPluginData } from "knub";
|
||||||
import { MutesPluginType } from "../types";
|
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;
|
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 { Case } from "../../../data/entities/Case";
|
||||||
import { LogsPlugin } from "../../../plugins/Logs/LogsPlugin";
|
import { LogsPlugin } from "../../../plugins/Logs/LogsPlugin";
|
||||||
import { muteLock } from "../../../utils/lockNameHelpers";
|
import { muteLock } from "../../../utils/lockNameHelpers";
|
||||||
|
import { TextChannel, User } from "discord.js";
|
||||||
|
|
||||||
export async function muteUser(
|
export async function muteUser(
|
||||||
pluginData: GuildPluginData<MutesPluginType>,
|
pluginData: GuildPluginData<MutesPluginType>,
|
||||||
|
@ -58,8 +59,8 @@ export async function muteUser(
|
||||||
if (member) {
|
if (member) {
|
||||||
const logs = pluginData.getPlugin(LogsPlugin);
|
const logs = pluginData.getPlugin(LogsPlugin);
|
||||||
// remove and store any roles to be removed/restored
|
// remove and store any roles to be removed/restored
|
||||||
const currentUserRoles = member.roles;
|
const currentUserRoles = member.roles.cache.keyArray();
|
||||||
const memberOptions: MemberOptions = {};
|
let newRoles: string[] = currentUserRoles;
|
||||||
const removeRoles = removeRolesOnMuteOverride ?? config.remove_roles_on_mute;
|
const removeRoles = removeRolesOnMuteOverride ?? config.remove_roles_on_mute;
|
||||||
const restoreRoles = restoreRolesOnMuteOverride ?? config.restore_roles_on_mute;
|
const restoreRoles = restoreRolesOnMuteOverride ?? config.restore_roles_on_mute;
|
||||||
|
|
||||||
|
@ -67,13 +68,13 @@ export async function muteUser(
|
||||||
if (!Array.isArray(removeRoles)) {
|
if (!Array.isArray(removeRoles)) {
|
||||||
if (removeRoles) {
|
if (removeRoles) {
|
||||||
// exclude managed roles from being removed
|
// exclude managed roles from being removed
|
||||||
const managedRoles = pluginData.guild.roles.filter(x => x.managed).map(y => y.id);
|
const managedRoles = pluginData.guild.roles.cache.filter(x => x.managed).map(y => y.id);
|
||||||
memberOptions.roles = managedRoles.filter(x => member.roles.includes(x));
|
newRoles = currentUserRoles.filter(r => !managedRoles.includes(r));
|
||||||
await member.edit(memberOptions);
|
await member.roles.set(newRoles);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
memberOptions.roles = currentUserRoles.filter(x => !(<string[]>removeRoles).includes(x));
|
newRoles = currentUserRoles.filter(x => !(<string[]>removeRoles).includes(x));
|
||||||
await member.edit(memberOptions);
|
await member.roles.set(newRoles);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set roles to be restored
|
// set roles to be restored
|
||||||
|
@ -86,11 +87,11 @@ export async function muteUser(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply mute role if it's missing
|
// Apply mute role if it's missing
|
||||||
if (!member.roles.includes(muteRole)) {
|
if (!currentUserRoles.includes(muteRole)) {
|
||||||
try {
|
try {
|
||||||
await member.addRole(muteRole);
|
await member.roles.add(muteRole);
|
||||||
} catch (e) {
|
} 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) {
|
if (!actualMuteRole) {
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
logs.log(LogType.BOT_ALERT, {
|
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 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 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();
|
lock.unlock();
|
||||||
logs.log(LogType.BOT_ALERT, {
|
logs.log(LogType.BOT_ALERT, {
|
||||||
body: `Cannot mute user ${member.id}: ${e}`,
|
body: `Cannot mute user ${member.id}: ${e}`,
|
||||||
|
@ -125,7 +126,7 @@ export async function muteUser(
|
||||||
if (moveToVoiceChannel || cfg.kick_from_voice_channel) {
|
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
|
// TODO: Add back the voiceState check once we figure out how to get voice state for guild members that are loaded on-demand
|
||||||
try {
|
try {
|
||||||
await member.edit({ channelID: moveToVoiceChannel });
|
await member.edit({ channel: moveToVoiceChannel });
|
||||||
} catch {} // tslint:disable-line
|
} catch {} // tslint:disable-line
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,18 +36,17 @@ export async function unmuteUser(
|
||||||
const lock = await pluginData.locks.acquire(memberRolesLock(member));
|
const lock = await pluginData.locks.acquire(memberRolesLock(member));
|
||||||
|
|
||||||
const muteRole = pluginData.config.get().mute_role;
|
const muteRole = pluginData.config.get().mute_role;
|
||||||
if (muteRole && member.roles.includes(muteRole)) {
|
if (muteRole && member.roles.cache.has(muteRole)) {
|
||||||
await member.removeRole(muteRole);
|
await member.roles.remove(muteRole);
|
||||||
member.roles = member.roles.filter(r => r !== muteRole);
|
|
||||||
}
|
}
|
||||||
if (existingMute?.roles_to_restore) {
|
if (existingMute?.roles_to_restore) {
|
||||||
const memberOptions: MemberOptions = {};
|
const guildRoles = pluginData.guild.roles.cache;
|
||||||
const guildRoles = pluginData.guild.roles;
|
let newRoles: string[] = member.roles.cache.keyArray();
|
||||||
memberOptions.roles = Array.from(
|
newRoles = muteRole && newRoles.includes(muteRole) ? newRoles.splice(newRoles.indexOf(muteRole), 1) : newRoles;
|
||||||
new Set([...existingMute.roles_to_restore, ...member.roles.filter(x => x !== muteRole && guildRoles.has(x))]),
|
for (const toRestore of existingMute.roles_to_restore) {
|
||||||
);
|
if (guildRoles.has(toRestore) && toRestore !== muteRole) newRoles.push(toRestore);
|
||||||
await member.edit(memberOptions);
|
}
|
||||||
member.roles = memberOptions.roles;
|
await member.roles.set(newRoles);
|
||||||
}
|
}
|
||||||
|
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
@ -85,7 +84,7 @@ export async function unmuteUser(
|
||||||
});
|
});
|
||||||
|
|
||||||
// Log the action
|
// Log the action
|
||||||
const mod = pluginData.client.user!.get(modId);
|
const mod = pluginData.client.users.fetch(modId);
|
||||||
if (unmuteTime) {
|
if (unmuteTime) {
|
||||||
pluginData.state.serverLogs.log(LogType.MEMBER_TIMED_UNMUTE, {
|
pluginData.state.serverLogs.log(LogType.MEMBER_TIMED_UNMUTE, {
|
||||||
mod: stripObjectToScalars(mod),
|
mod: stripObjectToScalars(mod),
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { GuildMutes } from "../../data/GuildMutes";
|
||||||
import { CaseArgs } from "../Cases/types";
|
import { CaseArgs } from "../Cases/types";
|
||||||
import Timeout = NodeJS.Timeout;
|
import Timeout = NodeJS.Timeout;
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
|
import { GuildMember } from "discord.js";
|
||||||
|
|
||||||
export const ConfigSchema = t.type({
|
export const ConfigSchema = t.type({
|
||||||
mute_role: tNullable(t.string),
|
mute_role: tNullable(t.string),
|
||||||
|
@ -58,7 +59,7 @@ export interface MutesPluginType extends BasePluginType {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMuteWithDetails extends Mute {
|
export interface IMuteWithDetails extends Mute {
|
||||||
member?: Member;
|
member?: GuildMember;
|
||||||
banned?: boolean;
|
banned?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ export const NamesCmd = nameHistoryCmd({
|
||||||
);
|
);
|
||||||
const usernameRows = usernames.map(r => `\`[${r.timestamp}]\` **${disableCodeBlocks(r.username)}**`);
|
const usernameRows = usernames.map(r => `\`[${r.timestamp}]\` **${disableCodeBlocks(r.username)}**`);
|
||||||
|
|
||||||
const user = pluginData.client.user!.get(args.userId);
|
const user = await pluginData.client.users.fetch(args.userId);
|
||||||
const currentUsername = user ? `${user.username}#${user.discriminator}` : args.userId;
|
const currentUsername = user ? `${user.username}#${user.discriminator}` : args.userId;
|
||||||
|
|
||||||
const nicknameDays = Math.round(NICKNAME_RETENTION_PERIOD / DAYS);
|
const nicknameDays = Math.round(NICKNAME_RETENTION_PERIOD / DAYS);
|
||||||
|
|
|
@ -2,10 +2,15 @@ import { nameHistoryEvt } from "../types";
|
||||||
import { updateNickname } from "../updateNickname";
|
import { updateNickname } from "../updateNickname";
|
||||||
|
|
||||||
export const ChannelJoinEvt = nameHistoryEvt({
|
export const ChannelJoinEvt = nameHistoryEvt({
|
||||||
event: "voiceChannelJoin",
|
event: "voiceStateUpdate",
|
||||||
|
|
||||||
async listener(meta) {
|
async listener(meta) {
|
||||||
meta.pluginData.state.updateQueue.add(() => updateNickname(meta.pluginData, meta.args.member));
|
meta.pluginData.state.updateQueue.add(() =>
|
||||||
|
updateNickname(
|
||||||
|
meta.pluginData,
|
||||||
|
meta.args.newState.member ? meta.args.newState.member : meta.args.oldState.member!,
|
||||||
|
),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
|
import { GuildMember } from "discord.js";
|
||||||
import { GuildPluginData } from "knub";
|
import { GuildPluginData } from "knub";
|
||||||
import { NameHistoryPluginType } from "./types";
|
import { NameHistoryPluginType } from "./types";
|
||||||
|
|
||||||
export async function updateNickname(pluginData: GuildPluginData<NameHistoryPluginType>, member: Member) {
|
export async function updateNickname(pluginData: GuildPluginData<NameHistoryPluginType>, member: GuildMember) {
|
||||||
if (!member) return;
|
if (!member) return;
|
||||||
const latestEntry = await pluginData.state.nicknameHistory.getLastEntry(member.id);
|
const latestEntry = await pluginData.state.nicknameHistory.getLastEntry(member.id);
|
||||||
if (!latestEntry || latestEntry.nickname !== member.nick) {
|
if (!latestEntry || latestEntry.nickname !== member.nickname) {
|
||||||
if (!latestEntry && member.nick == null) return; // No need to save "no nickname" if there's no previous data
|
if (!latestEntry && member.nickname == null) return; // No need to save "no nickname" if there's no previous data
|
||||||
await pluginData.state.nicknameHistory.addEntry(member.id, member.nick);
|
await pluginData.state.nicknameHistory.addEntry(member.id, member.nickname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,9 @@ import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||||
import { missingPermissionError } from "../../../utils/missingPermissionError";
|
import { missingPermissionError } from "../../../utils/missingPermissionError";
|
||||||
import { canAssignRole } from "../../../utils/canAssignRole";
|
import { canAssignRole } from "../../../utils/canAssignRole";
|
||||||
import { memberRolesLock } from "../../../utils/lockNameHelpers";
|
import { memberRolesLock } from "../../../utils/lockNameHelpers";
|
||||||
|
import { GuildMemberEditData, Permissions } from "discord.js";
|
||||||
|
|
||||||
const p = Constants.Permissions;
|
const p = Permissions.FLAGS;
|
||||||
|
|
||||||
export const LoadDataEvt = persistEvt({
|
export const LoadDataEvt = persistEvt({
|
||||||
event: "guildMemberAdd",
|
event: "guildMemberAdd",
|
||||||
|
@ -26,16 +27,16 @@ export const LoadDataEvt = persistEvt({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const toRestore: MemberOptions = {};
|
let toRestore: GuildMemberEditData = {};
|
||||||
const config = await pluginData.config.getForMember(member);
|
const config = await pluginData.config.getForMember(member);
|
||||||
const restoredData: string[] = [];
|
const restoredData: string[] = [];
|
||||||
|
|
||||||
// Check permissions
|
// Check permissions
|
||||||
const me = pluginData.guild.members.cache.get(pluginData.client.user!.id)!;
|
const me = pluginData.guild.members.cache.get(pluginData.client.user!.id)!;
|
||||||
let requiredPermissions = 0n;
|
let requiredPermissions = 0n;
|
||||||
if (config.persist_nicknames) requiredPermissions |= p.manageNicknames;
|
if (config.persist_nicknames) requiredPermissions |= p.MANAGE_NICKNAMES;
|
||||||
if (config.persisted_roles) requiredPermissions |= p.manageRoles;
|
if (config.persisted_roles) requiredPermissions |= p.MANAGE_ROLES;
|
||||||
const missingPermissions = getMissingPermissions(me.permission, requiredPermissions);
|
const missingPermissions = getMissingPermissions(me.permissions, requiredPermissions);
|
||||||
if (missingPermissions) {
|
if (missingPermissions) {
|
||||||
pluginData.getPlugin(LogsPlugin).log(LogType.BOT_ALERT, {
|
pluginData.getPlugin(LogsPlugin).log(LogType.BOT_ALERT, {
|
||||||
body: `Missing permissions for persist plugin: ${missingPermissionError(missingPermissions)}`,
|
body: `Missing permissions for persist plugin: ${missingPermissionError(missingPermissions)}`,
|
||||||
|
@ -61,7 +62,7 @@ export const LoadDataEvt = persistEvt({
|
||||||
|
|
||||||
if (rolesToRestore.length) {
|
if (rolesToRestore.length) {
|
||||||
restoredData.push("roles");
|
restoredData.push("roles");
|
||||||
toRestore.roles = Array.from(new Set([...rolesToRestore, ...member.roles]));
|
toRestore.roles = Array.from(new Set([...rolesToRestore, ...member.roles.cache]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,13 @@ import { persistEvt } from "../types";
|
||||||
import { IPartialPersistData } from "../../../data/GuildPersistedData";
|
import { IPartialPersistData } from "../../../data/GuildPersistedData";
|
||||||
|
|
||||||
import intersection from "lodash.intersection";
|
import intersection from "lodash.intersection";
|
||||||
|
import { GuildMember } from "discord.js";
|
||||||
|
|
||||||
export const StoreDataEvt = persistEvt({
|
export const StoreDataEvt = persistEvt({
|
||||||
event: "guildMemberRemove",
|
event: "guildMemberRemove",
|
||||||
|
|
||||||
async listener(meta) {
|
async listener(meta) {
|
||||||
const member = meta.args.member as Member;
|
const member = meta.args.member as GuildMember;
|
||||||
const pluginData = meta.pluginData;
|
const pluginData = meta.pluginData;
|
||||||
|
|
||||||
let persist = false;
|
let persist = false;
|
||||||
|
@ -23,9 +24,9 @@ export const StoreDataEvt = persistEvt({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.persist_nicknames && member.nick) {
|
if (config.persist_nicknames && member.nickname) {
|
||||||
persist = true;
|
persist = true;
|
||||||
persistData.nickname = member.nick;
|
persistData.nickname = member.nickname;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (persist) {
|
if (persist) {
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { postCmd } from "../types";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
import { formatContent } from "../util/formatContent";
|
import { formatContent } from "../util/formatContent";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export const EditCmd = postCmd({
|
export const EditCmd = postCmd({
|
||||||
trigger: "edit",
|
trigger: "edit",
|
||||||
|
@ -24,7 +25,9 @@ export const EditCmd = postCmd({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await pluginData.client.editMessage(savedMessage.channel_id, savedMessage.id, formatContent(args.content));
|
(pluginData.guild.channels.cache.get(savedMessage.channel_id) as TextChannel).messages.edit(savedMessage.id, {
|
||||||
|
content: formatContent(args.content),
|
||||||
|
});
|
||||||
sendSuccessMessage(pluginData, msg.channel, "Message edited");
|
sendSuccessMessage(pluginData, msg.channel, "Message edited");
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { trimLines } from "../../../utils";
|
||||||
import { formatContent } from "../util/formatContent";
|
import { formatContent } from "../util/formatContent";
|
||||||
import { parseColor } from "../../../utils/parseColor";
|
import { parseColor } from "../../../utils/parseColor";
|
||||||
import { rgbToInt } from "../../../utils/rgbToInt";
|
import { rgbToInt } from "../../../utils/rgbToInt";
|
||||||
|
import { MessageEmbed, TextChannel } from "discord.js";
|
||||||
|
|
||||||
const COLOR_MATCH_REGEX = /^#?([0-9a-f]{6})$/;
|
const COLOR_MATCH_REGEX = /^#?([0-9a-f]{6})$/;
|
||||||
|
|
||||||
|
@ -42,17 +43,19 @@ export const EditEmbedCmd = postCmd({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const embed: Embed = savedMessage.data.embeds![0] as Embed;
|
const embed: MessageEmbed = savedMessage.data.embeds![0] as MessageEmbed;
|
||||||
if (args.title) embed.title = args.title;
|
if (args.title) embed.title = args.title;
|
||||||
if (content) embed.description = formatContent(content);
|
if (content) embed.description = formatContent(content);
|
||||||
if (color) embed.color = color;
|
if (color) embed.color = color;
|
||||||
|
|
||||||
await pluginData.client.editMessage(savedMessage.channel_id, savedMessage.id, { embed });
|
(pluginData.guild.channels.cache.get(savedMessage.channel_id) as TextChannel).messages.edit(savedMessage.id, {
|
||||||
|
embed,
|
||||||
|
});
|
||||||
await sendSuccessMessage(pluginData, msg.channel, "Embed edited");
|
await sendSuccessMessage(pluginData, msg.channel, "Embed edited");
|
||||||
|
|
||||||
if (args.content) {
|
if (args.content) {
|
||||||
const prefix = pluginData.fullConfig.prefix || "!";
|
const prefix = pluginData.fullConfig.prefix || "!";
|
||||||
msg.channel.createMessage(
|
msg.channel.send(
|
||||||
trimLines(`
|
trimLines(`
|
||||||
<@!${msg.author.id}> You can now specify an embed's content directly at the end of the command:
|
<@!${msg.author.id}> You can now specify an embed's content directly at the end of the command:
|
||||||
\`${prefix}edit_embed -title "Some title" content goes here\`
|
\`${prefix}edit_embed -title "Some title" content goes here\`
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { isValidEmbed, trimLines } from "../../../utils";
|
||||||
import { formatContent } from "../util/formatContent";
|
import { formatContent } from "../util/formatContent";
|
||||||
import { parseColor } from "../../../utils/parseColor";
|
import { parseColor } from "../../../utils/parseColor";
|
||||||
import { rgbToInt } from "../../../utils/rgbToInt";
|
import { rgbToInt } from "../../../utils/rgbToInt";
|
||||||
|
import { MessageEmbed, MessageEmbedOptions } from "discord.js";
|
||||||
|
|
||||||
export const PostEmbedCmd = postCmd({
|
export const PostEmbedCmd = postCmd({
|
||||||
trigger: "post_embed",
|
trigger: "post_embed",
|
||||||
|
@ -46,7 +47,7 @@ export const PostEmbedCmd = postCmd({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let embed: Embed = { type: "rich" };
|
let embed: MessageEmbedOptions = {};
|
||||||
if (args.title) embed.title = args.title;
|
if (args.title) embed.title = args.title;
|
||||||
if (color) embed.color = color;
|
if (color) embed.color = color;
|
||||||
|
|
||||||
|
@ -73,7 +74,7 @@ export const PostEmbedCmd = postCmd({
|
||||||
|
|
||||||
if (args.content) {
|
if (args.content) {
|
||||||
const prefix = pluginData.fullConfig.prefix || "!";
|
const prefix = pluginData.fullConfig.prefix || "!";
|
||||||
msg.channel.createMessage(
|
msg.channel.send(
|
||||||
trimLines(`
|
trimLines(`
|
||||||
<@!${msg.author.id}> You can now specify an embed's content directly at the end of the command:
|
<@!${msg.author.id}> You can now specify an embed's content directly at the end of the command:
|
||||||
\`${prefix}edit_embed -title "Some title" content goes here\`
|
\`${prefix}edit_embed -title "Some title" content goes here\`
|
||||||
|
|
|
@ -20,7 +20,7 @@ export const ScheduledPostsListCmd = postCmd({
|
||||||
async run({ message: msg, pluginData }) {
|
async run({ message: msg, pluginData }) {
|
||||||
const scheduledPosts = await pluginData.state.scheduledPosts.all();
|
const scheduledPosts = await pluginData.state.scheduledPosts.all();
|
||||||
if (scheduledPosts.length === 0) {
|
if (scheduledPosts.length === 0) {
|
||||||
msg.channel.createMessage("No scheduled posts");
|
msg.channel.send("No scheduled posts");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { sorter } from "../../../utils";
|
||||||
import { sendErrorMessage } from "../../../pluginUtils";
|
import { sendErrorMessage } from "../../../pluginUtils";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { postMessage } from "../util/postMessage";
|
import { postMessage } from "../util/postMessage";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
export const ScheduledPostsShowCmd = postCmd({
|
export const ScheduledPostsShowCmd = postCmd({
|
||||||
trigger: ["scheduled_posts", "scheduled_posts show"],
|
trigger: ["scheduled_posts", "scheduled_posts show"],
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { PostPluginType } from "../types";
|
||||||
import { parseScheduleTime } from "./parseScheduleTime";
|
import { parseScheduleTime } from "./parseScheduleTime";
|
||||||
import { postMessage } from "./postMessage";
|
import { postMessage } from "./postMessage";
|
||||||
import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin";
|
import { TimeAndDatePlugin } from "../../TimeAndDate/TimeAndDatePlugin";
|
||||||
|
import { Message, Channel, TextChannel } from "discord.js";
|
||||||
|
|
||||||
const MIN_REPEAT_TIME = 5 * MINUTES;
|
const MIN_REPEAT_TIME = 5 * MINUTES;
|
||||||
const MAX_REPEAT_TIME = Math.pow(2, 32);
|
const MAX_REPEAT_TIME = Math.pow(2, 32);
|
||||||
|
@ -27,22 +28,30 @@ export async function actualPostCmd(
|
||||||
} = {},
|
} = {},
|
||||||
) {
|
) {
|
||||||
if (!(targetChannel instanceof TextChannel)) {
|
if (!(targetChannel instanceof TextChannel)) {
|
||||||
msg.channel.createMessage(errorMessage("Channel is not a text channel"));
|
msg.channel.send(errorMessage("Channel is not a text channel"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (content == null && msg.attachments.length === 0) {
|
if (content == null && msg.attachments.size === 0) {
|
||||||
msg.channel.createMessage(errorMessage("Message content or attachment required"));
|
msg.channel.send(errorMessage("Message content or attachment required"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.repeat) {
|
if (opts.repeat) {
|
||||||
if (opts.repeat < MIN_REPEAT_TIME) {
|
if (opts.repeat < MIN_REPEAT_TIME) {
|
||||||
sendErrorMessage(pluginData, msg.channel, `Minimum time for -repeat is ${humanizeDuration(MIN_REPEAT_TIME)}`);
|
sendErrorMessage(
|
||||||
|
pluginData,
|
||||||
|
msg.channel as TextChannel,
|
||||||
|
`Minimum time for -repeat is ${humanizeDuration(MIN_REPEAT_TIME)}`,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (opts.repeat > MAX_REPEAT_TIME) {
|
if (opts.repeat > MAX_REPEAT_TIME) {
|
||||||
sendErrorMessage(pluginData, msg.channel, `Max time for -repeat is ${humanizeDuration(MAX_REPEAT_TIME)}`);
|
sendErrorMessage(
|
||||||
|
pluginData,
|
||||||
|
msg.channel as TextChannel,
|
||||||
|
`Max time for -repeat is ${humanizeDuration(MAX_REPEAT_TIME)}`,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +62,7 @@ export async function actualPostCmd(
|
||||||
// Schedule the post to be posted later
|
// Schedule the post to be posted later
|
||||||
postAt = await parseScheduleTime(pluginData, msg.author.id, opts.schedule);
|
postAt = await parseScheduleTime(pluginData, msg.author.id, opts.schedule);
|
||||||
if (!postAt) {
|
if (!postAt) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Invalid schedule time");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "Invalid schedule time");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (opts.repeat) {
|
} else if (opts.repeat) {
|
||||||
|
@ -70,17 +79,17 @@ export async function actualPostCmd(
|
||||||
|
|
||||||
// Invalid time
|
// Invalid time
|
||||||
if (!repeatUntil) {
|
if (!repeatUntil) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Invalid time specified for -repeat-until");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "Invalid time specified for -repeat-until");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (repeatUntil.isBefore(moment.utc())) {
|
if (repeatUntil.isBefore(moment.utc())) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "You can't set -repeat-until in the past");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "You can't set -repeat-until in the past");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (repeatUntil.isAfter(MAX_REPEAT_UNTIL)) {
|
if (repeatUntil.isAfter(MAX_REPEAT_UNTIL)) {
|
||||||
sendErrorMessage(
|
sendErrorMessage(
|
||||||
pluginData,
|
pluginData,
|
||||||
msg.channel,
|
msg.channel as TextChannel,
|
||||||
"Unfortunately, -repeat-until can only be at most 100 years into the future. Maybe 99 years would be enough?",
|
"Unfortunately, -repeat-until can only be at most 100 years into the future. Maybe 99 years would be enough?",
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
@ -88,18 +97,26 @@ export async function actualPostCmd(
|
||||||
} else if (opts["repeat-times"]) {
|
} else if (opts["repeat-times"]) {
|
||||||
repeatTimes = opts["repeat-times"];
|
repeatTimes = opts["repeat-times"];
|
||||||
if (repeatTimes <= 0) {
|
if (repeatTimes <= 0) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "-repeat-times must be 1 or more");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "-repeat-times must be 1 or more");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (repeatUntil && repeatTimes) {
|
if (repeatUntil && repeatTimes) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "You can only use one of -repeat-until or -repeat-times at once");
|
sendErrorMessage(
|
||||||
|
pluginData,
|
||||||
|
msg.channel as TextChannel,
|
||||||
|
"You can only use one of -repeat-until or -repeat-times at once",
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.repeat && !repeatUntil && !repeatTimes) {
|
if (opts.repeat && !repeatUntil && !repeatTimes) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "You must specify -repeat-until or -repeat-times for repeated messages");
|
sendErrorMessage(
|
||||||
|
pluginData,
|
||||||
|
msg.channel as TextChannel,
|
||||||
|
"You must specify -repeat-until or -repeat-times for repeated messages",
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +131,7 @@ export async function actualPostCmd(
|
||||||
// Save schedule/repeat information in DB
|
// Save schedule/repeat information in DB
|
||||||
if (postAt) {
|
if (postAt) {
|
||||||
if (postAt < moment.utc()) {
|
if (postAt < moment.utc()) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Post can't be scheduled to be posted in the past");
|
sendErrorMessage(pluginData, msg.channel as TextChannel, "Post can't be scheduled to be posted in the past");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +140,7 @@ export async function actualPostCmd(
|
||||||
author_name: `${msg.author.username}#${msg.author.discriminator}`,
|
author_name: `${msg.author.username}#${msg.author.discriminator}`,
|
||||||
channel_id: targetChannel.id,
|
channel_id: targetChannel.id,
|
||||||
content,
|
content,
|
||||||
attachments: msg.attachments,
|
attachments: msg.attachments.array(),
|
||||||
post_at: postAt
|
post_at: postAt
|
||||||
.clone()
|
.clone()
|
||||||
.tz("Etc/UTC")
|
.tz("Etc/UTC")
|
||||||
|
@ -162,7 +179,7 @@ export async function actualPostCmd(
|
||||||
|
|
||||||
// When the message isn't scheduled for later, post it immediately
|
// When the message isn't scheduled for later, post it immediately
|
||||||
if (!opts.schedule) {
|
if (!opts.schedule) {
|
||||||
await postMessage(pluginData, targetChannel, content, msg.attachments, opts["enable-mentions"]);
|
await postMessage(pluginData, targetChannel, content, msg.attachments.array(), opts["enable-mentions"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.repeat) {
|
if (opts.repeat) {
|
||||||
|
@ -197,6 +214,6 @@ export async function actualPostCmd(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetChannel.id !== msg.channel.id || opts.schedule || opts.repeat) {
|
if (targetChannel.id !== msg.channel.id || opts.schedule || opts.repeat) {
|
||||||
sendSuccessMessage(pluginData, msg.channel, successMessage);
|
sendSuccessMessage(pluginData, msg.channel as TextChannel, successMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,15 @@ import { PostPluginType } from "../types";
|
||||||
import { downloadFile } from "../../../utils";
|
import { downloadFile } from "../../../utils";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import { formatContent } from "./formatContent";
|
import { formatContent } from "./formatContent";
|
||||||
|
import { TextChannel, Message, MessageOptions, MessageAttachment } from "discord.js";
|
||||||
|
|
||||||
const fsp = fs.promises;
|
const fsp = fs.promises;
|
||||||
|
|
||||||
export async function postMessage(
|
export async function postMessage(
|
||||||
pluginData: GuildPluginData<PostPluginType>,
|
pluginData: GuildPluginData<PostPluginType>,
|
||||||
channel: TextChannel,
|
channel: TextChannel,
|
||||||
content: MessageContent,
|
content: MessageOptions,
|
||||||
attachments: Attachment[] = [],
|
attachments: MessageAttachment[] = [],
|
||||||
enableMentions: boolean = false,
|
enableMentions: boolean = false,
|
||||||
): Promise<Message> {
|
): Promise<Message> {
|
||||||
if (typeof content === "string") {
|
if (typeof content === "string") {
|
||||||
|
@ -27,20 +28,18 @@ export async function postMessage(
|
||||||
if (attachments.length) {
|
if (attachments.length) {
|
||||||
downloadedAttachment = await downloadFile(attachments[0].url);
|
downloadedAttachment = await downloadFile(attachments[0].url);
|
||||||
file = {
|
file = {
|
||||||
name: attachments[0].filename,
|
name: attachments[0].name,
|
||||||
file: await fsp.readFile(downloadedAttachment.path),
|
file: await fsp.readFile(downloadedAttachment.path),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enableMentions) {
|
if (enableMentions) {
|
||||||
content.allowedMentions = {
|
content.allowedMentions = {
|
||||||
everyone: true,
|
parse: ["everyone", "roles", "users"],
|
||||||
users: true,
|
|
||||||
roles: true,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const createdMsg = await channel.createMessage(content, file);
|
const createdMsg = await channel.send(content, file);
|
||||||
pluginData.state.savedMessages.setPermanent(createdMsg.id);
|
pluginData.state.savedMessages.setPermanent(createdMsg.id);
|
||||||
|
|
||||||
if (downloadedAttachment) {
|
if (downloadedAttachment) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { LogType } from "../../../data/LogType";
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
|
|
||||||
import { postMessage } from "./postMessage";
|
import { postMessage } from "./postMessage";
|
||||||
|
import { TextChannel, User } from "discord.js";
|
||||||
|
|
||||||
const SCHEDULED_POST_CHECK_INTERVAL = 5 * SECONDS;
|
const SCHEDULED_POST_CHECK_INTERVAL = 5 * SECONDS;
|
||||||
|
|
||||||
|
@ -15,7 +16,7 @@ export async function scheduledPostLoop(pluginData: GuildPluginData<PostPluginTy
|
||||||
const channel = pluginData.guild.channels.cache.get(post.channel_id);
|
const channel = pluginData.guild.channels.cache.get(post.channel_id);
|
||||||
if (channel instanceof TextChannel) {
|
if (channel instanceof TextChannel) {
|
||||||
const [username, discriminator] = post.author_name.split("#");
|
const [username, discriminator] = post.author_name.split("#");
|
||||||
const author: Partial<User> = pluginData.client.user!.get(post.author_id) || {
|
const author: User = (await pluginData.client.users.fetch(post.author_id)) || {
|
||||||
id: post.author_id,
|
id: post.author_id,
|
||||||
username,
|
username,
|
||||||
discriminator,
|
discriminator,
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
|
|
||||||
import { isDiscordRESTError } from "../../../utils";
|
import { isDiscordRESTError } from "../../../utils";
|
||||||
|
import { Message } from "discord.js";
|
||||||
|
|
||||||
export const ClearReactionRolesCmd = reactionRolesCmd({
|
export const ClearReactionRolesCmd = reactionRolesCmd({
|
||||||
trigger: "reaction_roles clear",
|
trigger: "reaction_roles clear",
|
||||||
|
@ -21,9 +22,9 @@ export const ClearReactionRolesCmd = reactionRolesCmd({
|
||||||
|
|
||||||
pluginData.state.reactionRoles.removeFromMessage(args.message.messageId);
|
pluginData.state.reactionRoles.removeFromMessage(args.message.messageId);
|
||||||
|
|
||||||
let targetMessage: Message<TextChannel>;
|
let targetMessage: Message;
|
||||||
try {
|
try {
|
||||||
targetMessage = await args.message.channel.getMessage(args.message.messageId);
|
targetMessage = await args.message.channel.messages.fetch(args.message.messageId);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (isDiscordRESTError(err) && err.code === 50001) {
|
if (isDiscordRESTError(err) && err.code === 50001) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Missing access to the specified message");
|
sendErrorMessage(pluginData, msg.channel, "Missing access to the specified message");
|
||||||
|
@ -33,7 +34,7 @@ export const ClearReactionRolesCmd = reactionRolesCmd({
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
await targetMessage.removeReactions();
|
await targetMessage.reactions.removeAll();
|
||||||
|
|
||||||
sendSuccessMessage(pluginData, msg.channel, "Reaction roles cleared");
|
sendSuccessMessage(pluginData, msg.channel, "Reaction roles cleared");
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import { reactionRolesCmd, TReactionRolePair } from "../types";
|
import { reactionRolesCmd, TReactionRolePair } from "../types";
|
||||||
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
import { commandTypeHelpers as ct } from "../../../commandTypes";
|
||||||
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
import { sendErrorMessage, sendSuccessMessage } from "../../../pluginUtils";
|
||||||
|
|
||||||
import { RecoverablePluginError, ERRORS } from "../../../RecoverablePluginError";
|
|
||||||
import { canUseEmoji, isDiscordRESTError, isValidEmoji, noop, trimPluginDescription } from "../../../utils";
|
import { canUseEmoji, isDiscordRESTError, isValidEmoji, noop, trimPluginDescription } from "../../../utils";
|
||||||
import { applyReactionRoleReactionsToMessage } from "../util/applyReactionRoleReactionsToMessage";
|
import { applyReactionRoleReactionsToMessage } from "../util/applyReactionRoleReactionsToMessage";
|
||||||
import { canReadChannel } from "../../../utils/canReadChannel";
|
import { canReadChannel } from "../../../utils/canReadChannel";
|
||||||
|
@ -41,7 +39,7 @@ export const InitReactionRolesCmd = reactionRolesCmd({
|
||||||
|
|
||||||
let targetMessage;
|
let targetMessage;
|
||||||
try {
|
try {
|
||||||
targetMessage = await args.message.channel.getMessage(args.message.messageId).catch(noop);
|
targetMessage = await args.message.channel.messages.fetch(args.message.messageId).catch(noop);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (isDiscordRESTError(e)) {
|
if (isDiscordRESTError(e)) {
|
||||||
sendErrorMessage(pluginData, msg.channel, `Error ${e.code} while getting message: ${e.message}`);
|
sendErrorMessage(pluginData, msg.channel, `Error ${e.code} while getting message: ${e.message}`);
|
||||||
|
@ -96,13 +94,13 @@ export const InitReactionRolesCmd = reactionRolesCmd({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pluginData.guild.roles.has(pair[1])) {
|
if (!pluginData.guild.roles.cache.has(pair[1])) {
|
||||||
sendErrorMessage(pluginData, msg.channel, `Unknown role ${pair[1]}`);
|
sendErrorMessage(pluginData, msg.channel, `Unknown role ${pair[1]}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const progressMessage = msg.channel.createMessage("Adding reaction roles...");
|
const progressMessage = msg.channel.send("Adding reaction roles...");
|
||||||
|
|
||||||
// Save the new reaction roles to the database
|
// Save the new reaction roles to the database
|
||||||
for (const pair of emojiRolePairs) {
|
for (const pair of emojiRolePairs) {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { addMemberPendingRoleChange } from "../util/addMemberPendingRoleChange";
|
||||||
|
|
||||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
|
import { Message } from "discord.js";
|
||||||
|
|
||||||
const CLEAR_ROLES_EMOJI = "❌";
|
const CLEAR_ROLES_EMOJI = "❌";
|
||||||
|
|
||||||
|
@ -12,9 +13,9 @@ export const AddReactionRoleEvt = reactionRolesEvt({
|
||||||
|
|
||||||
async listener(meta) {
|
async listener(meta) {
|
||||||
const pluginData = meta.pluginData;
|
const pluginData = meta.pluginData;
|
||||||
const msg = meta.args.message as Message;
|
const msg = meta.args.reaction.message as Message;
|
||||||
const emoji = meta.args.emoji;
|
const emoji = meta.args.reaction.emoji;
|
||||||
const userId = meta.args.member.id;
|
const userId = meta.args.user.id;
|
||||||
|
|
||||||
if (userId === pluginData.client.user!.id) {
|
if (userId === pluginData.client.user!.id) {
|
||||||
// Don't act on own reactions
|
// Don't act on own reactions
|
||||||
|
@ -39,7 +40,7 @@ export const AddReactionRoleEvt = reactionRolesEvt({
|
||||||
// User reacted with a reaction role emoji -> add the role
|
// User reacted with a reaction role emoji -> add the role
|
||||||
const matchingReactionRole = await pluginData.state.reactionRoles.getByMessageAndEmoji(
|
const matchingReactionRole = await pluginData.state.reactionRoles.getByMessageAndEmoji(
|
||||||
msg.id,
|
msg.id,
|
||||||
emoji.id || emoji.name,
|
emoji.id || emoji.name!,
|
||||||
);
|
);
|
||||||
if (!matchingReactionRole) return;
|
if (!matchingReactionRole) return;
|
||||||
|
|
||||||
|
@ -59,9 +60,8 @@ export const AddReactionRoleEvt = reactionRolesEvt({
|
||||||
if (config.remove_user_reactions) {
|
if (config.remove_user_reactions) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
pluginData.state.reactionRemoveQueue.add(async () => {
|
pluginData.state.reactionRemoveQueue.add(async () => {
|
||||||
const reaction = emoji.id ? `${emoji.name}:${emoji.id}` : emoji.name;
|
|
||||||
const wait = sleep(1500);
|
const wait = sleep(1500);
|
||||||
await msg.channel.removeMessageReaction(msg.id, reaction, userId).catch(noop);
|
await meta.args.reaction.remove().catch(noop);
|
||||||
await wait;
|
await wait;
|
||||||
});
|
});
|
||||||
}, 1500);
|
}, 1500);
|
||||||
|
|
|
@ -23,7 +23,7 @@ export async function addMemberPendingRoleChange(
|
||||||
|
|
||||||
const member = await resolveMember(pluginData.client, pluginData.guild, memberId);
|
const member = await resolveMember(pluginData.client, pluginData.guild, memberId);
|
||||||
if (member) {
|
if (member) {
|
||||||
const newRoleIds = new Set(member.roles);
|
const newRoleIds = new Set(member.roles.cache.keyArray());
|
||||||
for (const change of newPendingRoleChangeObj.changes) {
|
for (const change of newPendingRoleChangeObj.changes) {
|
||||||
if (change.mode === "+") newRoleIds.add(change.roleId);
|
if (change.mode === "+") newRoleIds.add(change.roleId);
|
||||||
else newRoleIds.delete(change.roleId);
|
else newRoleIds.delete(change.roleId);
|
||||||
|
@ -38,7 +38,7 @@ export async function addMemberPendingRoleChange(
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
`Failed to apply role changes to ${member.username}#${member.discriminator} (${member.id}): ${e.message}`,
|
`Failed to apply role changes to ${member.user.username}#${member.user.discriminator} (${member.id}): ${e.message}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { isDiscordRESTError, sleep, isSnowflake } from "../../../utils";
|
||||||
import { logger } from "../../../logger";
|
import { logger } from "../../../logger";
|
||||||
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
import { LogsPlugin } from "../../Logs/LogsPlugin";
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
const CLEAR_ROLES_EMOJI = "❌";
|
const CLEAR_ROLES_EMOJI = "❌";
|
||||||
|
|
||||||
|
@ -26,7 +27,7 @@ export async function applyReactionRoleReactionsToMessage(
|
||||||
|
|
||||||
let targetMessage;
|
let targetMessage;
|
||||||
try {
|
try {
|
||||||
targetMessage = await channel.getMessage(messageId);
|
targetMessage = await channel.messages.fetch(messageId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (isDiscordRESTError(e)) {
|
if (isDiscordRESTError(e)) {
|
||||||
if (e.code === 10008) {
|
if (e.code === 10008) {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import moment from "moment-timezone";
|
||||||
import humanizeDuration from "humanize-duration";
|
import humanizeDuration from "humanize-duration";
|
||||||
import { disableLinkPreviews } from "knub/dist/helpers";
|
import { disableLinkPreviews } from "knub/dist/helpers";
|
||||||
import { SECONDS } from "../../../utils";
|
import { SECONDS } from "../../../utils";
|
||||||
|
import { TextChannel } from "discord.js";
|
||||||
|
|
||||||
const REMINDER_LOOP_TIME = 10 * SECONDS;
|
const REMINDER_LOOP_TIME = 10 * SECONDS;
|
||||||
const MAX_TRIES = 3;
|
const MAX_TRIES = 3;
|
||||||
|
@ -19,7 +20,7 @@ export async function postDueRemindersLoop(pluginData: GuildPluginData<Reminders
|
||||||
const target = moment.utc();
|
const target = moment.utc();
|
||||||
const diff = target.diff(moment.utc(reminder.created_at, "YYYY-MM-DD HH:mm:ss"));
|
const diff = target.diff(moment.utc(reminder.created_at, "YYYY-MM-DD HH:mm:ss"));
|
||||||
const result = humanizeDuration(diff, { largest: 2, round: true });
|
const result = humanizeDuration(diff, { largest: 2, round: true });
|
||||||
await channel.createMessage({
|
await channel.send({
|
||||||
content: disableLinkPreviews(
|
content: disableLinkPreviews(
|
||||||
`Reminder for <@!${reminder.user_id}>: ${reminder.body} \n\`Set at ${reminder.created_at} (${result} ago)\``,
|
`Reminder for <@!${reminder.user_id}>: ${reminder.body} \n\`Set at ${reminder.created_at} (${result} ago)\``,
|
||||||
),
|
),
|
||||||
|
@ -28,7 +29,7 @@ export async function postDueRemindersLoop(pluginData: GuildPluginData<Reminders
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await channel.createMessage({
|
await channel.send({
|
||||||
content: disableLinkPreviews(`Reminder for <@!${reminder.user_id}>: ${reminder.body}`),
|
content: disableLinkPreviews(`Reminder for <@!${reminder.user_id}>: ${reminder.body}`),
|
||||||
allowedMentions: {
|
allowedMentions: {
|
||||||
users: [reminder.user_id],
|
users: [reminder.user_id],
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { sendErrorMessage, sendSuccessMessage, canActOn } from "../../../pluginU
|
||||||
import { rolesCmd } from "../types";
|
import { rolesCmd } from "../types";
|
||||||
import { resolveRoleId, stripObjectToScalars, verboseUserMention } from "../../../utils";
|
import { resolveRoleId, stripObjectToScalars, verboseUserMention } from "../../../utils";
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
|
import { GuildChannel } from "discord.js";
|
||||||
|
|
||||||
export const AddRoleCmd = rolesCmd({
|
export const AddRoleCmd = rolesCmd({
|
||||||
trigger: "addrole",
|
trigger: "addrole",
|
||||||
|
@ -33,7 +34,7 @@ export const AddRoleCmd = rolesCmd({
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanity check: make sure the role is configured properly
|
// Sanity check: make sure the role is configured properly
|
||||||
const role = (msg.channel as GuildChannel).guild.roles.get(roleId);
|
const role = (msg.channel as GuildChannel).guild.roles.cache.get(roleId);
|
||||||
if (!role) {
|
if (!role) {
|
||||||
pluginData.state.logs.log(LogType.BOT_ALERT, {
|
pluginData.state.logs.log(LogType.BOT_ALERT, {
|
||||||
body: `Unknown role configured for 'roles' plugin: ${roleId}`,
|
body: `Unknown role configured for 'roles' plugin: ${roleId}`,
|
||||||
|
@ -42,14 +43,14 @@ export const AddRoleCmd = rolesCmd({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.member.roles.includes(roleId)) {
|
if (args.member.roles.cache.has(roleId)) {
|
||||||
sendErrorMessage(pluginData, msg.channel, "Member already has that role");
|
sendErrorMessage(pluginData, msg.channel, "Member already has that role");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pluginData.state.logs.ignoreLog(LogType.MEMBER_ROLE_ADD, args.member.id);
|
pluginData.state.logs.ignoreLog(LogType.MEMBER_ROLE_ADD, args.member.id);
|
||||||
|
|
||||||
await args.member.addRole(roleId);
|
await args.member.roles.add(roleId);
|
||||||
|
|
||||||
pluginData.state.logs.log(LogType.MEMBER_ROLE_ADD, {
|
pluginData.state.logs.log(LogType.MEMBER_ROLE_ADD, {
|
||||||
member: stripObjectToScalars(args.member, ["user", "roles"]),
|
member: stripObjectToScalars(args.member, ["user", "roles"]),
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { rolesCmd } from "../types";
|
||||||
import { resolveMember, resolveRoleId, stripObjectToScalars, successMessage } from "../../../utils";
|
import { resolveMember, resolveRoleId, stripObjectToScalars, successMessage } from "../../../utils";
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
import { logger } from "../../../logger";
|
import { logger } from "../../../logger";
|
||||||
|
import { GuildMember } from "discord.js";
|
||||||
|
|
||||||
export const MassAddRoleCmd = rolesCmd({
|
export const MassAddRoleCmd = rolesCmd({
|
||||||
trigger: "massaddrole",
|
trigger: "massaddrole",
|
||||||
|
@ -15,9 +16,9 @@ export const MassAddRoleCmd = rolesCmd({
|
||||||
},
|
},
|
||||||
|
|
||||||
async run({ message: msg, args, pluginData }) {
|
async run({ message: msg, args, pluginData }) {
|
||||||
msg.channel.createMessage(`Resolving members...`);
|
msg.channel.send(`Resolving members...`);
|
||||||
|
|
||||||
const members: Member[] = [];
|
const members: GuildMember[] = [];
|
||||||
const unknownMembers: string[] = [];
|
const unknownMembers: string[] = [];
|
||||||
for (const memberId of args.members) {
|
for (const memberId of args.members) {
|
||||||
const member = await resolveMember(pluginData.client, pluginData.guild, memberId);
|
const member = await resolveMember(pluginData.client, pluginData.guild, memberId);
|
||||||
|
@ -57,12 +58,12 @@ export const MassAddRoleCmd = rolesCmd({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const membersWithoutTheRole = members.filter(m => !m.roles.includes(roleId));
|
const membersWithoutTheRole = members.filter(m => !m.roles.cache.has(roleId));
|
||||||
let assigned = 0;
|
let assigned = 0;
|
||||||
const failed: string[] = [];
|
const failed: string[] = [];
|
||||||
const alreadyHadRole = members.length - membersWithoutTheRole.length;
|
const alreadyHadRole = members.length - membersWithoutTheRole.length;
|
||||||
|
|
||||||
msg.channel.createMessage(
|
msg.channel.send(
|
||||||
`Adding role **${role.name}** to ${membersWithoutTheRole.length} ${
|
`Adding role **${role.name}** to ${membersWithoutTheRole.length} ${
|
||||||
membersWithoutTheRole.length === 1 ? "member" : "members"
|
membersWithoutTheRole.length === 1 ? "member" : "members"
|
||||||
}...`,
|
}...`,
|
||||||
|
@ -71,7 +72,7 @@ export const MassAddRoleCmd = rolesCmd({
|
||||||
for (const member of membersWithoutTheRole) {
|
for (const member of membersWithoutTheRole) {
|
||||||
try {
|
try {
|
||||||
pluginData.state.logs.ignoreLog(LogType.MEMBER_ROLE_ADD, member.id);
|
pluginData.state.logs.ignoreLog(LogType.MEMBER_ROLE_ADD, member.id);
|
||||||
await member.addRole(roleId);
|
await member.roles.add(roleId);
|
||||||
pluginData.state.logs.log(LogType.MEMBER_ROLE_ADD, {
|
pluginData.state.logs.log(LogType.MEMBER_ROLE_ADD, {
|
||||||
member: stripObjectToScalars(member, ["user", "roles"]),
|
member: stripObjectToScalars(member, ["user", "roles"]),
|
||||||
roles: role.name,
|
roles: role.name,
|
||||||
|
@ -97,6 +98,6 @@ export const MassAddRoleCmd = rolesCmd({
|
||||||
resultMessage += `\nUnknown members: ${unknownMembers.join(", ")}`;
|
resultMessage += `\nUnknown members: ${unknownMembers.join(", ")}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.channel.createMessage(successMessage(resultMessage));
|
msg.channel.send(successMessage(resultMessage));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { rolesCmd } from "../types";
|
||||||
import { resolveMember, stripObjectToScalars, successMessage, resolveRoleId } from "../../../utils";
|
import { resolveMember, stripObjectToScalars, successMessage, resolveRoleId } from "../../../utils";
|
||||||
import { LogType } from "../../../data/LogType";
|
import { LogType } from "../../../data/LogType";
|
||||||
import { logger } from "../../../logger";
|
import { logger } from "../../../logger";
|
||||||
|
import { GuildMember } from "discord.js";
|
||||||
|
|
||||||
export const MassRemoveRoleCmd = rolesCmd({
|
export const MassRemoveRoleCmd = rolesCmd({
|
||||||
trigger: "massremoverole",
|
trigger: "massremoverole",
|
||||||
|
@ -15,9 +16,9 @@ export const MassRemoveRoleCmd = rolesCmd({
|
||||||
},
|
},
|
||||||
|
|
||||||
async run({ message: msg, args, pluginData }) {
|
async run({ message: msg, args, pluginData }) {
|
||||||
msg.channel.createMessage(`Resolving members...`);
|
msg.channel.send(`Resolving members...`);
|
||||||
|
|
||||||
const members: Member[] = [];
|
const members: GuildMember[] = [];
|
||||||
const unknownMembers: string[] = [];
|
const unknownMembers: string[] = [];
|
||||||
for (const memberId of args.members) {
|
for (const memberId of args.members) {
|
||||||
const member = await resolveMember(pluginData.client, pluginData.guild, memberId);
|
const member = await resolveMember(pluginData.client, pluginData.guild, memberId);
|
||||||
|
@ -57,12 +58,12 @@ export const MassRemoveRoleCmd = rolesCmd({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const membersWithTheRole = members.filter(m => m.roles.includes(roleId));
|
const membersWithTheRole = members.filter(m => m.roles.cache.has(roleId));
|
||||||
let assigned = 0;
|
let assigned = 0;
|
||||||
const failed: string[] = [];
|
const failed: string[] = [];
|
||||||
const didNotHaveRole = members.length - membersWithTheRole.length;
|
const didNotHaveRole = members.length - membersWithTheRole.length;
|
||||||
|
|
||||||
msg.channel.createMessage(
|
msg.channel.send(
|
||||||
`Removing role **${role.name}** from ${membersWithTheRole.length} ${
|
`Removing role **${role.name}** from ${membersWithTheRole.length} ${
|
||||||
membersWithTheRole.length === 1 ? "member" : "members"
|
membersWithTheRole.length === 1 ? "member" : "members"
|
||||||
}...`,
|
}...`,
|
||||||
|
@ -71,7 +72,7 @@ export const MassRemoveRoleCmd = rolesCmd({
|
||||||
for (const member of membersWithTheRole) {
|
for (const member of membersWithTheRole) {
|
||||||
try {
|
try {
|
||||||
pluginData.state.logs.ignoreLog(LogType.MEMBER_ROLE_REMOVE, member.id);
|
pluginData.state.logs.ignoreLog(LogType.MEMBER_ROLE_REMOVE, member.id);
|
||||||
await member.removeRole(roleId);
|
await member.roles.remove(roleId);
|
||||||
pluginData.state.logs.log(LogType.MEMBER_ROLE_REMOVE, {
|
pluginData.state.logs.log(LogType.MEMBER_ROLE_REMOVE, {
|
||||||
member: stripObjectToScalars(member, ["user", "roles"]),
|
member: stripObjectToScalars(member, ["user", "roles"]),
|
||||||
roles: role.name,
|
roles: role.name,
|
||||||
|
@ -97,6 +98,6 @@ export const MassRemoveRoleCmd = rolesCmd({
|
||||||
resultMessage += `\nUnknown members: ${unknownMembers.join(", ")}`;
|
resultMessage += `\nUnknown members: ${unknownMembers.join(", ")}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.channel.createMessage(successMessage(resultMessage));
|
msg.channel.send(successMessage(resultMessage));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue