diff --git a/src/structures/GuildAuditLogs.js b/src/structures/GuildAuditLogs.js index ad0039028..5c9859480 100644 --- a/src/structures/GuildAuditLogs.js +++ b/src/structures/GuildAuditLogs.js @@ -1,6 +1,7 @@ const Collection = require('../util/Collection'); const Snowflake = require('../util/Snowflake'); const Webhook = require('./Webhook'); +const Integration = require('./Integration'); const Invite = require('./Invite'); /** @@ -13,6 +14,7 @@ const Invite = require('./Invite'); * * WEBHOOK * * EMOJI * * MESSAGE + * * INTEGRATION * @typedef {string} AuditLogTargetType */ @@ -31,6 +33,8 @@ const Targets = { WEBHOOK: 'WEBHOOK', EMOJI: 'EMOJI', MESSAGE: 'MESSAGE', + INTEGRATION: 'INTEGRATION', + UNKNOWN: 'UNKNOWN', }; /** @@ -49,6 +53,9 @@ const Targets = { * * MEMBER_BAN_REMOVE: 23 * * MEMBER_UPDATE: 24 * * MEMBER_ROLE_UPDATE: 25 + * * MEMBER_MOVE: 26 + * * MEMBER_DISCONNECT: 27 + * * BOT_ADD: 28, * * ROLE_CREATE: 30 * * ROLE_UPDATE: 31 * * ROLE_DELETE: 32 @@ -62,6 +69,12 @@ const Targets = { * * EMOJI_UPDATE: 61 * * EMOJI_DELETE: 62 * * MESSAGE_DELETE: 72 + * * MESSAGE_BULK_DELETE: 73 + * * MESSAGE_PIN: 74 + * * MESSAGE_UNPIN: 75 + * * INTEGRATION_CREATE: 80 + * * INTEGRATION_UPDATE: 81 + * * INTEGRATION_DELETE: 82 * @typedef {?number|string} AuditLogAction */ @@ -85,6 +98,9 @@ const Actions = { MEMBER_BAN_REMOVE: 23, MEMBER_UPDATE: 24, MEMBER_ROLE_UPDATE: 25, + MEMBER_MOVE: 26, + MEMBER_DISCONNECT: 27, + BOT_ADD: 28, ROLE_CREATE: 30, ROLE_UPDATE: 31, ROLE_DELETE: 32, @@ -98,6 +114,12 @@ const Actions = { EMOJI_UPDATE: 61, EMOJI_DELETE: 62, MESSAGE_DELETE: 72, + MESSAGE_BULK_DELETE: 73, + MESSAGE_PIN: 74, + MESSAGE_UNPIN: 75, + INTEGRATION_CREATE: 80, + INTEGRATION_UPDATE: 81, + INTEGRATION_DELETE: 82, }; @@ -120,6 +142,18 @@ class GuildAuditLogs { } } + /** + * Cached integrations + * @type {Collection} + * @private + */ + this.integrations = new Collection(); + if (data.integrations) { + for (const integration of data.integrations) { + this.integrations.set(integration.id, new Integration(guild.client, integration, guild)); + } + } + /** * The entries for this guild's audit logs * @type {Collection} @@ -148,9 +182,10 @@ class GuildAuditLogs { * * An emoji * * An invite * * A webhook + * * An integration * * An object with an id key if target was deleted * * An object where the keys represent either the new value or the old value - * @typedef {?Object|Guild|User|Role|Emoji|Invite|Webhook} AuditLogEntryTarget + * @typedef {?Object|Guild|User|Role|Emoji|Invite|Webhook|Integration} AuditLogEntryTarget */ /** @@ -167,6 +202,7 @@ class GuildAuditLogs { if (target < 60) return Targets.WEBHOOK; if (target < 70) return Targets.EMOJI; if (target < 80) return Targets.MESSAGE; + if (target < 90) return Targets.INTEGRATION; return null; } @@ -190,10 +226,13 @@ class GuildAuditLogs { Actions.CHANNEL_CREATE, Actions.CHANNEL_OVERWRITE_CREATE, Actions.MEMBER_BAN_REMOVE, + Actions.BOT_ADD, Actions.ROLE_CREATE, Actions.INVITE_CREATE, Actions.WEBHOOK_CREATE, Actions.EMOJI_CREATE, + Actions.MESSAGE_PIN, + Actions.INTEGRATION_CREATE, ].includes(action)) return 'CREATE'; if ([ @@ -202,11 +241,15 @@ class GuildAuditLogs { Actions.MEMBER_KICK, Actions.MEMBER_PRUNE, Actions.MEMBER_BAN_ADD, + Actions.MEMBER_DISCONNECT, Actions.ROLE_DELETE, Actions.INVITE_DELETE, Actions.WEBHOOK_DELETE, Actions.EMOJI_DELETE, Actions.MESSAGE_DELETE, + Actions.MESSAGE_BULK_DELETE, + Actions.MESSAGE_UNPIN, + Actions.INTEGRATION_DELETE, ].includes(action)) return 'DELETE'; if ([ @@ -215,10 +258,12 @@ class GuildAuditLogs { Actions.CHANNEL_OVERWRITE_UPDATE, Actions.MEMBER_UPDATE, Actions.MEMBER_ROLE_UPDATE, + Actions.MEMBER_MOVE, Actions.ROLE_UPDATE, Actions.INVITE_UPDATE, Actions.WEBHOOK_UPDATE, Actions.EMOJI_UPDATE, + Actions.INTEGRATION_UPDATE, ].includes(action)) return 'UPDATE'; return 'ALL'; @@ -229,6 +274,7 @@ class GuildAuditLogs { * Audit logs entry. */ class GuildAuditLogsEntry { + // eslint-disable-next-line complexity constructor(logs, guild, data) { const targetType = GuildAuditLogs.targetType(data.action_type); /** @@ -286,39 +332,74 @@ class GuildAuditLogsEntry { * @type {?Object|Role|GuildMember} */ this.extra = null; - if (data.options) { - if (data.action_type === Actions.MEMBER_PRUNE) { + switch (data.action_type) { + case Actions.MEMBER_PRUNE: this.extra = { - removed: data.options.members_removed, - days: data.options.delete_member_days, + removed: Number(data.options.members_removed), + days: Number(data.options.delete_member_days), }; - } else if (data.action_type === Actions.MESSAGE_DELETE) { + break; + + case Actions.MEMBER_MOVE: + case Actions.MESSAGE_DELETE: + case Actions.MESSAGE_BULK_DELETE: this.extra = { - count: data.options.count, - channel: guild.channels.get(data.options.channel_id), + channel: guild.channels.get(data.options.channel_id) || { id: data.options.channel_id }, + count: Number(data.options.count), }; - } else { + break; + + case Actions.MESSAGE_PIN: + case Actions.MESSAGE_UNPIN: + this.extra = { + channel: guild.client.channels.get(data.options.channel_id) || { id: data.options.channel_id }, + messageID: data.options.message_id, + }; + break; + + case Actions.MEMBER_DISCONNECT: + this.extra = { + count: Number(data.options.count), + }; + break; + + case Actions.CHANNEL_OVERWRITE_CREATE: + case Actions.CHANNEL_OVERWRITE_UPDATE: + case Actions.CHANNEL_OVERWRITE_DELETE: switch (data.options.type) { case 'member': - this.extra = guild.members.get(data.options.id); - if (!this.extra) this.extra = { id: data.options.id }; + this.extra = guild.members.get(data.options.id) || + { id: data.options.id, type: 'member' }; break; case 'role': - this.extra = guild.roles.get(data.options.id); - if (!this.extra) this.extra = { id: data.options.id, name: data.options.role_name }; + this.extra = guild.roles.get(data.options.id) || + { id: data.options.id, name: data.options.role_name, type: 'role' }; break; default: break; } - } + break; + + default: + break; } - if ([Targets.USER, Targets.GUILD].includes(targetType)) { - /** - * The target of this entry - * @type {AuditLogEntryTarget} - */ - this.target = guild.client[`${targetType.toLowerCase()}s`].get(data.target_id); + /** + * The target of this entry + * @type {AuditLogEntryTarget} + */ + this.target = null; + if (targetType === Targets.UNKNOWN) { + this.changes.reduce((o, c) => { + o[c.key] = c.new || c.old; + return o; + }, {}); + this.target.id = data.target_id; + // MEMBER_DISCONNECT and similar types do not provide a target_id. + } else if (targetType === Targets.USER && data.target_id) { + this.target = guild.client.users.get(data.target_id); + } else if (targetType === Targets.GUILD) { + this.target = guild.client.guilds.get(data.target_id); } else if (targetType === Targets.WEBHOOK) { this.target = logs.webhooks.get(data.target_id) || new Webhook(guild.client, @@ -340,8 +421,17 @@ class GuildAuditLogsEntry { changes.channel = { id: changes.channel_id }; this.target = new Invite(guild.client, changes); } else if (targetType === Targets.MESSAGE) { - this.target = guild.client.users.get(data.target_id); - } else { + // Discord sends a channel id for the MESSAGE_BULK_DELETE action type. + this.target = data.action_type === Actions.MESSAGE_BULK_DELETE ? + guild.channels.get(data.target_id) || { id: data.target_id } : + guild.client.users.get(data.target_id); + } else if (targetType === Targets.INTEGRATION) { + this.target = logs.integrations.get(data.target_id) || + new Integration(guild.client, this.changes.reduce((o, c) => { + o[c.key] = c.new || c.old; + return o; + }, { id: data.target_id }), guild); + } else if (data.target_id) { this.target = guild[`${targetType.toLowerCase()}s`].get(data.target_id) || { id: data.target_id }; } } diff --git a/typings/index.d.ts b/typings/index.d.ts index 8dcc99a30..ca89c54a2 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -601,6 +601,7 @@ declare module 'discord.js' { export class GuildAuditLogs { constructor(guild: Guild, data: object); private webhooks: Collection; + private integrations: Collection; public entries: Collection; @@ -623,7 +624,7 @@ declare module 'discord.js' { public extra: object | Role | GuildMember; public id: Snowflake; public reason: string; - public target: Guild | User | Role | Emoji | Invite | Webhook; + public target: Guild | User | Role | Emoji | Invite | Webhook | Integration | null; public targetType: GuildAuditLogsTarget; } @@ -1868,6 +1869,9 @@ declare module 'discord.js' { MEMBER_BAN_REMOVE?: number; MEMBER_UPDATE?: number; MEMBER_ROLE_UPDATE?: number; + MEMBER_MOVE?: number; + MEMBER_DISCONNECT?: number; + BOT_ADD?: number; ROLE_CREATE?: number; ROLE_UPDATE?: number; ROLE_DELETE?: number; @@ -1881,6 +1885,12 @@ declare module 'discord.js' { EMOJI_UPDATE?: number; EMOJI_DELETE?: number; MESSAGE_DELETE?: number; + MESSAGE_BULK_DELETE?: number; + MESSAGE_PIN?: number; + MESSAGE_UNPIN?: number; + INTEGRATION_CREATE?: number; + INTEGRATION_UPDATE?: number; + INTEGRATION_DELETE?: number; }; type GuildAuditLogsActionType = 'CREATE' @@ -1908,6 +1918,8 @@ declare module 'discord.js' { WEBHOOK?: string; EMOJI?: string; MESSAGE?: string; + INTEGRATION?: string; + UNKNOWN?: string; }; type GuildChannelMessageNotifications = MessageNotifications