feat(links): unlink every Steam id before an account is deleted (MODULE_API 1.20.0)
ACCOUNT_DELETION.md §4.4 (AD10). api.onUserDeleting calls links.unlinkForDeletion, which runs the player's own unlinkOwned per link, logs rust.account.unlink with reason 'account deleted', and marks every server's permission sync dirty so the withdrawn grants reach the game on the next tick. coreApi ^1.20.0; core-ref pinned to website#232's merge (7bd93b8); engagement manifest regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
const core = require('../../core')
|
||||
const db = require('./links.db')
|
||||
const engagement = require('../../engagement/emit')
|
||||
const permissionsDb = require('../permissions/permissions.db')
|
||||
const servers = require('../servers/servers.model')
|
||||
const serversDb = require('../servers/servers.db')
|
||||
const sidecar = require('../../sidecarClient')
|
||||
@@ -351,6 +352,47 @@ async function linkFromSteamSignin({ userId, provider, subject, displayName }) {
|
||||
engagement.linked({ userId, steamId, name: displayName || null })
|
||||
}
|
||||
|
||||
// ── The website account is being deleted (MODULE_API 1.20.0) ──────────────
|
||||
//
|
||||
// ACCOUNT_DELETION.md §4.4. Core asks before the users row goes, while the
|
||||
// person's links can still be read (AD10). The cascade on `rust_account_links`
|
||||
// would remove the rows anyway; calling the real unlink keeps what a cascade
|
||||
// skips — the `rust.account.unlink` entry staff read and the prompt Teams
|
||||
// re-sync — so the game sees exactly what a player's own unlink produces.
|
||||
|
||||
/**
|
||||
* Core's `api.onUserDeleting`: unlink every Steam id this account holds.
|
||||
*
|
||||
* The same `unlinkOwned` the player's Rust page calls, one link at a time, each
|
||||
* logged as `rust.account.unlink` with `reason: 'account deleted'`. Then every
|
||||
* server's permission sync is marked dirty: the desired set reaches a grant's
|
||||
* Steam id through the link, so with the links gone the grants have already
|
||||
* left it, and the next tick pushes the withdrawal instead of waiting for the
|
||||
* digest check.
|
||||
*
|
||||
* Nothing here waits on a game. The link is the site's own record and the plugin
|
||||
* keeps none (the header above), so there is never pending work: what this does
|
||||
* not finish, the cascade does.
|
||||
*/
|
||||
async function unlinkForDeletion({ userId, deletedBy }) {
|
||||
const held = await db.listForUser(userId)
|
||||
let removed = 0
|
||||
for (const row of held) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
if (await unlinkOwned(row.steamId, userId)) {
|
||||
removed += 1
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await core.activity.log({
|
||||
userId,
|
||||
action: 'rust.account.unlink',
|
||||
detail: { steamId: row.steamId, reason: 'account deleted', deletedBy },
|
||||
})
|
||||
}
|
||||
}
|
||||
if (removed > 0) await permissionsDb.markDirty(null)
|
||||
log.info('rust links removed before an account was deleted', { userId, deletedBy, removed })
|
||||
}
|
||||
|
||||
/** The admin panel's read: every link this user holds, with per-server totals. */
|
||||
async function forAdmin(userId) {
|
||||
const links = await db.listForUserWithPlayer(userId)
|
||||
@@ -393,5 +435,6 @@ module.exports = {
|
||||
unlinkFromGame,
|
||||
checkSteamSignin,
|
||||
linkFromSteamSignin,
|
||||
unlinkForDeletion,
|
||||
forAdmin,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user