discord.js: GuildChannel#permissionsLocked incorrect when parent category updated
Please describe the problem you are having in as much detail as possible:
Assume a situation where a text channel is in a category, with the channel’s permissions set in Discord to sync with the category.
Accessing GuildChannel#permissionsLocked
for that channel will confirm this.
Now, assume that the permissions overwrites in the category are updated, and you have an event listener set for channel updates.
First, you will see the update come through for the category permissions overwrites being updated, which is all fine (or is it).
Then, you will see the update come through for the channel’s permissions overwrites being updated. At this point though, if you access GuildChannel#permissionsLocked
on the old channel, it will report that the permissions were not locked, even though they were, and GuildChannel#permissionsLocked
on the new channel will report that the permissions are not locked.
This happens (from my understanding) because we’ve already received the update event for the category overwrites changing, so both the old and new channel in the channel update event have the same, already updated, category as their parent which is used for the GuildChannel#permissionsLocked
calculation.
Include a reproducible code sample here, if possible:
client.on('channelUpdate', (oldChannel, newChannel) => {
const permsUpdated = newChannel.permissionOverwrites.size !== oldChannel.permissionOverwrites.size
|| newChannel.permissionOverwrites.some(overwrite => !oldChannel.permissionOverwrites.has(overwrite.id)
|| !oldChannel.permissionOverwrites.get(overwrite.id).allow.equals(overwrite.allow)
|| !oldChannel.permissionOverwrites.get(overwrite.id).deny.equals(overwrite.deny));
if (!permsUpdated) return;
if (newChannel.type === 'category') {
console.log('Category permissions updated');
return;
}
if (newChannel.type === 'text') {
console.log('Text channel permissions updated');
console.log('Synced before update:', oldChannel.permissionsLocked);
console.log('Synced after update:', newChannel.permissionsLocked);
return;
}
});
Further details:
- discord.js version: 13.0.0 (dev)
- Node.js version: 14.15.4
- Operating system: macOS
- Priority this issue should have – please be realistic and elaborate if possible: P2 – its an annoying issue that I’d love to see a fix or workaround for, but also somewhat minor
Relevant client options:
-
partials: channel (though both
GuildChannel
andChannel
do not have apartial
prop) -
gateway intents: guilds
-
other: none
-
I have also tested the issue on latest master, commit hash:
fe6cc0c15dde99caa1049d35f75b9335ace1721d
About this issue
- Original URL
- State: open
- Created 3 years ago
- Comments: 27 (15 by maintainers)
permissionsLocked
here isn’t a clear value though - the API doesn’t provide a boolean telling us that a channel is synced or not. It’s a getter that compares the channel’s overwrites to the parent’s overwrites at runtime. Because it’s a runtime check, there’s several reasons this simply can’t be accurate.oldChildChannel.permissionsLocked
would be comparing to the current, updated parent channels overwrites. I don’t think its even possible to freeze the parent’s old state for this, or somehow freeze the value of this getter, since as you said, the event for the update on the category is already processed before the children emit.The closest thing I can think of to a solution would be some mess where when the Category is updated it checks all its children, sees if they’re currently synced, and creates some sort of
oldParent
,oldParentOverwrites
oroldPermissionsLocked
on those channels before doing its own update, purely so that value could be used when the child event emits.Side note - since this isn’t a proper API-provided boolean doesnt this mean it can return a false positive if a parent and child have the same overwrites without being in sync?
I recommend creating a PR though so that proposed changes to solve this issue can be discussed there, directly on your proposed changes, rather than in the issue 😃
To put it in simple terms, no, this doesn’t sound like it solves the issue. It sounds like you’re removing the concept of permissions overwrites on channels, which makes no sense at all.
Yup, that sounds like the right theory.
No, it does not defeat the purpose… the whole idea here is that I want to be able to accurately report when a channel has its permissions updated in such a way that means the permissions are no longer set to sync, or have been updated when they were previously not in sync and are now in sync.
This current behaviour results in continual false positives, as the value of
permissionsLocked
switches indicating that the sync of the channel permissions was updated, when in reality the option to sync wasn’t updated, the permissions were in fact updating to remain in syc.Yes 👍, because they were still set to be synced, and were updated in exactly the same way the parent was, as they are synced.
Yes, based on the current logic, it is the expected behaviour. However, given that
permissionsLocked
is a helper provided by D.js rather than by Discord, it would be nice for it to be improved, so that it can handle this situation and correctly reflect that the permissions were set to be in sync the whole time.Yup, as I noticed two replies above, with recent changes to master I believe it is now
permissionOverwrites.cache.some
…No, the parent is updated first. If you run my repro code locally you will be able to observe the parent update event arrives first, which updates the d.js cache for both the parent and therefore the child. The child update event then arrives after, at which point the parent has already been updated and so the child is perceived as out of sync.
That is one consequence of the issue, yes, but it is not the root cause. The root cause is that the parent receives an update first, so when the child update comes through the child is perceived to be out of sync with the parent, when in reality the child is being updated because it is in sync with the parent.
https://discord.js.org/#/docs/collection/master/class/Collection?scrollTo=some
(This is now actually
permissionOverwrites.cache.some
per recent changes iirc)Nope, this still happens as of
f72ce7c136cf2dfe31a67b190c00e30ba7d70bfa
. I believe this is just how Discord sends the permissions updates for the parent channel and the children, but it would be nice if d.js handled it better.