Skip to content

Instantly share code, notes, and snippets.

@foxfirecodes
Last active August 31, 2020 21:28
Discord.js snippets for diffing changes of Discord permission overwrites

These are two potential scripts for computing (sane) diffs of permission overwrite changes on Discord channels with Discord.js.

bot.on('channelUpdate', (oldChannel, newChannel) => {
if (!oldChannel.guild) {
return
}
// get all roles/members that did or did not have overwrites:
const overwriteChanges = [...oldChannel.permissionOverwrites.keyArray(), ...newChannel.permissionOverwrites.keyArray()]
// filter out duplicate role/member IDs
.reduce((out, next) => out.includes(next) ? out : out.concat(next), [])
// map to pairs
.map(id => ({ id, before: oldChannel.permissionOverwrites.get(id), after: newChannel.permissionOverwrites.get(id) }))
// convert the PermissionOverwrites objects into easier to deal with null-safe types
.map(({ id, before, after }) => ({
id,
// get the overwrite type (role or member) from whichever object exists
type: before ? before.type : after.type,
before: {
// instead of having potentially null values for before/after, just use an empty array
allow: before ? before.allow.toArray() : [],
deny: before ? before.deny.toArray() : []
},
after: {
allow: after ? after.allow.toArray() : [],
deny: after ? after.deny.toArray() : []
}
}))
// find diffs
.map(({ id, type, before, after }) => ({
// preserve the ID & type
id,
type,
// compute permissions that are removed
// if the permission overwrite for the user/role wasn't deleted (after), filter out things that still exist (weren't deleted)
removed: [...before.allow, ...before.deny].filter(it => ![...after.allow, ...after.deny].includes(it)),
// if there are permission overwrites for the user/role after the update, make sure that anything that previously existed was removed
newlyAllowed: after.allow.filter(it => !before.allow.includes(it)),
newlyDenied: after.deny.filter(it => !before.deny.includes(it))
}))
// filter to only overwrites that changed in some way
.filter(({ removed, newlyAllowed, newlyDenied }) => removed.length || newlyAllowed.length || newlyDenied.length)
if (overwriteChanges.length < 1) {
// no changes happened to permission in this channel update, so ignore
return
}
// overwriteChanges is an array of permission overwrites that have changed, stored as objects in the format of:
// {
// id: string - the id of the role/member that changed
// type: string - either 'role' or 'member'
// removed: string[] - any permissions that are no longer allowed/denied
// newlyAllowed: string[] - the newly allowed permissions
// newlyDenied: string[] - the newly denied permissions
// }
console.log(`Received channel permission update for #${oldChannel.name} in ${oldChannel.guild.name}:`)
overwriteChanges.forEach(overwrite => console.log(overwrite))
});
bot.on('channelUpdate', (oldChannel, newChannel) => {
if (!oldChannel.guild) {
return
}
// get all roles/members that did or did not have overwrites:
const overwriteChanges = [...oldChannel.permissionOverwrites.keyArray(), ...newChannel.permissionOverwrites.keyArray()]
// filter out duplicate role/member IDs
.reduce((out, next) => out.includes(next) ? out : out.concat(next), [])
// map to pairs
.map(id => ({ id, before: oldChannel.permissionOverwrites.get(id), after: newChannel.permissionOverwrites.get(id) }))
// find diffs
.map(({ id, before, after }) => ({
// preserve the ID
id,
// get the overwrite type (role or member) from whichever object exists
type: before ? before.type : after.type,
removed: !before ? [] : [...before.allow.toArray(), ...before.deny.toArray()]
// if the permission overwrite for the user/role wasn't deleted (after), filter out things that still exist (weren't deleted)
.filter(it => after ? ![...after.allow.toArray(), ...after.deny.toArray()].includes(it) : true),
// if there are permission overwrites for the user/role after the update, make sure that anything that previously existed was removed
newlyAllowed: !after ? [] : (before ? after.allow.remove(before.allow) : after.allow).toArray(),
newlyDenied: !after ? [] : (before ? after.deny.remove(before.deny) : after.deny).toArray()
}))
// filter to only overwrites that changed in some way
.filter(({ removed, newlyAllowed, newlyDenied }) => removed.length || newlyAllowed.length || newlyDenied.length)
if (overwriteChanges.length < 1) {
// no changes happened to permission in this channel update, so ignore
return
}
// overwriteChanges is an array of permission overwrites that have changed, stored as objects in the format of:
// {
// id: string - the id of the role/member that changed
// type: string - either 'role' or 'member'
// removed: string[] - any permissions that are no longer allowed/denied
// newlyAllowed: string[] - the newly allowed permissions
// newlyDenied: string[] - the newly denied permissions
// }
console.log(`Received channel permission update for #${oldChannel.name} in ${oldChannel.guild.name}:`)
overwriteChanges.forEach(overwrite => console.log(overwrite))
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment