mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-25 14:34:36 +00:00
feat: kick_player can target a publicId (admin bot) (#4403)
## Description: Add an optional `targetPublicId` to KickPlayerIntent; the server resolves it against the connected clients to the live clientID, then kicks as before. Existing clientID targeting (lobby / in-game kick) is unchanged. That way you can kick player with both the clientID and playerID ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory ## Please put your Discord username so you can be contacted if a bug or regression is found: zixer._
This commit is contained in:
@@ -640,7 +640,7 @@ export class Transport {
|
||||
private onSendKickPlayerIntent(event: SendKickPlayerIntentEvent) {
|
||||
this.sendIntent({
|
||||
type: "kick_player",
|
||||
target: event.target,
|
||||
targetClientID: event.target,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -477,7 +477,11 @@ export const MarkDisconnectedIntentSchema = z.object({
|
||||
|
||||
export const KickPlayerIntentSchema = z.object({
|
||||
type: z.literal("kick_player"),
|
||||
target: ID,
|
||||
// Either a live clientID (lobby / in-game kick) OR an account publicID, for
|
||||
// callers that identify a player by account rather than per-session clientID;
|
||||
// the server resolves the publicID to the live clientID. Exactly one is set.
|
||||
targetClientID: ID.optional(),
|
||||
targetPublicID: ID.optional(),
|
||||
});
|
||||
|
||||
export const TogglePauseIntentSchema = z.object({
|
||||
|
||||
@@ -265,7 +265,19 @@ export class GameServer {
|
||||
error: "only the lobby creator or an admin can kick players",
|
||||
};
|
||||
}
|
||||
if (stamped.clientID === stamped.target) {
|
||||
// Resolve the target to a live clientID: an explicit clientID, or an
|
||||
// account publicId matched against the connected clients (for callers
|
||||
// that know the account but not the per-session clientID).
|
||||
let target = stamped.targetClientID;
|
||||
if (target === undefined && stamped.targetPublicID !== undefined) {
|
||||
target = this.activeClients.find(
|
||||
(c) => c.publicId === stamped.targetPublicID,
|
||||
)?.clientID;
|
||||
}
|
||||
if (target === undefined) {
|
||||
return { status: 404, error: "no matching player to kick" };
|
||||
}
|
||||
if (stamped.clientID === target) {
|
||||
return { status: 400, error: "cannot kick yourself" };
|
||||
}
|
||||
const reason =
|
||||
@@ -274,12 +286,12 @@ export class GameServer {
|
||||
: KICK_REASON_LOBBY_CREATOR;
|
||||
this.log.info("player kicked", {
|
||||
kicker: stamped.clientID,
|
||||
target: stamped.target,
|
||||
target,
|
||||
isAdmin: actor.isAdmin,
|
||||
isAdminBot: actor.isAdminBot,
|
||||
gameID: this.id,
|
||||
});
|
||||
this.kickClient(stamped.target, reason);
|
||||
this.kickClient(target, reason);
|
||||
return { status: 200 };
|
||||
}
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ describe("GameServer.handleIntent (admin bot)", () => {
|
||||
const spy = vi.spyOn(game, "kickClient");
|
||||
const result = apply(game, {
|
||||
type: "kick_player",
|
||||
target: "abcdABCD",
|
||||
targetClientID: "abcdABCD",
|
||||
} as any);
|
||||
expect(result.status).toBe(200);
|
||||
expect(spy).toHaveBeenCalledWith("abcdABCD", expect.any(String));
|
||||
@@ -126,10 +126,35 @@ describe("GameServer.handleIntent (admin bot)", () => {
|
||||
expect(
|
||||
apply(game, {
|
||||
type: "kick_player",
|
||||
target: "abcdABCD",
|
||||
targetClientID: "abcdABCD",
|
||||
} as any).status,
|
||||
).toBe(403);
|
||||
});
|
||||
|
||||
it("resolves a publicID target to the connected client's clientID", () => {
|
||||
const game = makeGame();
|
||||
(game as any).activeClients.push({
|
||||
clientID: "liveCID1",
|
||||
publicId: "pubABCD1",
|
||||
});
|
||||
const spy = vi.spyOn(game, "kickClient");
|
||||
const result = apply(game, {
|
||||
type: "kick_player",
|
||||
targetPublicID: "pubABCD1",
|
||||
} as any);
|
||||
expect(result.status).toBe(200);
|
||||
expect(spy).toHaveBeenCalledWith("liveCID1", expect.any(String));
|
||||
});
|
||||
|
||||
it("404s when no connected client matches the publicID", () => {
|
||||
const game = makeGame();
|
||||
expect(
|
||||
apply(game, {
|
||||
type: "kick_player",
|
||||
targetPublicID: "nobodyXX",
|
||||
} as any).status,
|
||||
).toBe(404);
|
||||
});
|
||||
});
|
||||
|
||||
describe("toggle_pause", () => {
|
||||
|
||||
@@ -93,7 +93,7 @@ describe("GameServer - kick_player authorization", () => {
|
||||
"message",
|
||||
JSON.stringify({
|
||||
type: "intent",
|
||||
intent: { type: "kick_player", target },
|
||||
intent: { type: "kick_player", targetClientID: target },
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user