escalation/de-escalation: keep ticket creator and /add'd users on the channel

enqueueMove called channel.setParent(categoryId, { lockPermissions: true }).
discord.js's default for setParent is also true. With lockPermissions: true,
Discord re-syncs the channel's permission overwrites to match the new
parent category — so the explicit per-user allows set at ticket creation
(creator) and via /add (extra members) got wiped on every escalate,
de-escalate, and /move. The creator literally lost View Channel on their
own ticket the moment staff hit Escalate.

Flip to lockPermissions: false so the existing channel-level overwrites
are preserved across the parent change. Inheritance still applies for
anything the channel doesn't override — and the deny-@everyone /
role-allow set at creation continues to gate access correctly.

Affects every caller of enqueueMove:
  - handlers/commands/escalation.js runEscalation
  - handlers/commands/escalation.js runDeescalation
  - handlers/commands/index.js handleMove (/move)
This commit is contained in:
2026-05-19 20:09:58 +00:00
parent c79463fc2a
commit 2152544d09

View File

@@ -83,6 +83,12 @@ function enqueueRename(channel, newName) {
// Shares renameChains so a move+rename pair on the same channel executes in
// call order. No coalescing: every move is a distinct chain link.
//
// lockPermissions: false preserves the channel's existing permission overwrites
// across the parent change. With the default (true), Discord re-syncs the
// channel's overwrites to match the new category and wipes per-user grants —
// in practice that kicked the ticket creator and any /add'd users off the
// channel on every escalate / de-escalate / /move.
function enqueueMove(channel, categoryId) {
let entry = renameChains.get(channel.id);
if (!entry) {
@@ -90,7 +96,7 @@ function enqueueMove(channel, categoryId) {
renameChains.set(channel.id, entry);
}
const next = entry.chain.catch(() => {}).then(() => channel.setParent(categoryId, { lockPermissions: true }));
const next = entry.chain.catch(() => {}).then(() => channel.setParent(categoryId, { lockPermissions: false }));
entry.chain = next;
next.catch((err) => {