mirror of
https://github.com/ericasch6/scrum-poker-internal.git
synced 2026-10-13 20:12:10 +00:00
Merge pull request #7 from ericasch6/codex/remove-moderator-throw-throttle
removed throttle for mod
This commit is contained in:
@@ -29,15 +29,17 @@ class RoomEmoteService
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$rateLimitKey = "room-emote:{$room->id}:{$player->id}";
|
if (! $player->isModerator()) {
|
||||||
|
$rateLimitKey = "room-emote:{$room->id}:{$player->id}";
|
||||||
|
|
||||||
abort_if(
|
abort_if(
|
||||||
RateLimiter::tooManyAttempts($rateLimitKey, 10),
|
RateLimiter::tooManyAttempts($rateLimitKey, 10),
|
||||||
429,
|
429,
|
||||||
'Bitte warte kurz, bevor du erneut wirfst.',
|
'Bitte warte kurz, bevor du erneut wirfst.',
|
||||||
);
|
);
|
||||||
|
|
||||||
RateLimiter::hit($rateLimitKey, 10);
|
RateLimiter::hit($rateLimitKey, 10);
|
||||||
|
}
|
||||||
|
|
||||||
PaperBallThrown::dispatch(
|
PaperBallThrown::dispatch(
|
||||||
Str::uuid()->toString(),
|
Str::uuid()->toString(),
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ const { activePaperBalls, hitPlayerIds, throwingAtPlayerId, throwPaperBall } =
|
|||||||
usePaperBallToss({
|
usePaperBallToss({
|
||||||
roomId: () => props.room.id,
|
roomId: () => props.room.id,
|
||||||
currentPlayerId: () => props.currentPlayer.id,
|
currentPlayerId: () => props.currentPlayer.id,
|
||||||
|
currentPlayerIsModerator: () => props.currentPlayer.is_moderator,
|
||||||
board: gameBoard,
|
board: gameBoard,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -115,7 +116,9 @@ const voteCount = computed(
|
|||||||
:revealed="room.revealed"
|
:revealed="room.revealed"
|
||||||
:presenter-mode="presenterMode"
|
:presenter-mode="presenterMode"
|
||||||
:is-paper-ball-hit="hitPlayerIds.includes(player.id)"
|
:is-paper-ball-hit="hitPlayerIds.includes(player.id)"
|
||||||
:throw-disabled="throwingAtPlayerId !== null"
|
:throw-disabled="
|
||||||
|
!currentPlayer.is_moderator && throwingAtPlayerId !== null
|
||||||
|
"
|
||||||
@throw-paper-ball="throwPaperBall"
|
@throw-paper-ball="throwPaperBall"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ const THROW_BUTTON_COOLDOWN = 550;
|
|||||||
export function usePaperBallToss({
|
export function usePaperBallToss({
|
||||||
roomId,
|
roomId,
|
||||||
currentPlayerId,
|
currentPlayerId,
|
||||||
|
currentPlayerIsModerator,
|
||||||
board,
|
board,
|
||||||
}: PaperBallTossOptions) {
|
}: PaperBallTossOptions) {
|
||||||
const activePaperBalls = ref<PaperBallFlight[]>([]);
|
const activePaperBalls = ref<PaperBallFlight[]>([]);
|
||||||
@@ -35,9 +36,11 @@ export function usePaperBallToss({
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function throwPaperBall(targetPlayerId: number): Promise<void> {
|
async function throwPaperBall(targetPlayerId: number): Promise<void> {
|
||||||
|
const shouldApplyCooldown = !currentPlayerIsModerator();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
targetPlayerId === currentPlayerId() ||
|
targetPlayerId === currentPlayerId() ||
|
||||||
throwingAtPlayerId.value !== null
|
(shouldApplyCooldown && throwingAtPlayerId.value !== null)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -52,7 +55,9 @@ export function usePaperBallToss({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
throwingAtPlayerId.value = targetPlayerId;
|
if (shouldApplyCooldown) {
|
||||||
|
throwingAtPlayerId.value = targetPlayerId;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(throwPaperBallRoute(roomId()).url, {
|
const response = await fetch(throwPaperBallRoute(roomId()).url, {
|
||||||
@@ -91,11 +96,13 @@ export function usePaperBallToss({
|
|||||||
} catch {
|
} catch {
|
||||||
toast.error('Der Papierknäuel konnte nicht geworfen werden.');
|
toast.error('Der Papierknäuel konnte nicht geworfen werden.');
|
||||||
} finally {
|
} finally {
|
||||||
schedule(() => {
|
if (shouldApplyCooldown) {
|
||||||
if (throwingAtPlayerId.value === targetPlayerId) {
|
schedule(() => {
|
||||||
throwingAtPlayerId.value = null;
|
if (throwingAtPlayerId.value === targetPlayerId) {
|
||||||
}
|
throwingAtPlayerId.value = null;
|
||||||
}, THROW_BUTTON_COOLDOWN);
|
}
|
||||||
|
}, THROW_BUTTON_COOLDOWN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export type PaperBallFlight = {
|
|||||||
export type PaperBallTossOptions = {
|
export type PaperBallTossOptions = {
|
||||||
roomId: () => string;
|
roomId: () => string;
|
||||||
currentPlayerId: () => number;
|
currentPlayerId: () => number;
|
||||||
|
currentPlayerIsModerator: () => boolean;
|
||||||
board: Ref<HTMLElement | null>;
|
board: Ref<HTMLElement | null>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,58 @@ test('a participant can throw a realtime paper ball at another player', function
|
|||||||
->and($room->state_version)->toBe($stateVersion);
|
->and($room->state_version)->toBe($stateVersion);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('moderator paper ball throws are not rate limited', function () {
|
||||||
|
Event::fake([PaperBallThrown::class]);
|
||||||
|
$room = createEmoteRoom();
|
||||||
|
$moderator = $room->players()->create([
|
||||||
|
'name' => 'Eric',
|
||||||
|
'is_moderator' => true,
|
||||||
|
]);
|
||||||
|
$target = $room->players()->create([
|
||||||
|
'name' => 'Anna',
|
||||||
|
'is_moderator' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
for ($throwCount = 0; $throwCount < 11; $throwCount++) {
|
||||||
|
$this->withSession(["room_players.{$room->id}" => $moderator->id])
|
||||||
|
->postJson(route('room.emote.paper-ball.store', $room), [
|
||||||
|
'target_player_id' => $target->id,
|
||||||
|
])
|
||||||
|
->assertNoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
Event::assertDispatchedTimes(PaperBallThrown::class, 11);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('participant paper ball throws remain rate limited', function () {
|
||||||
|
Event::fake([PaperBallThrown::class]);
|
||||||
|
$room = createEmoteRoom();
|
||||||
|
$moderator = $room->players()->create([
|
||||||
|
'name' => 'Eric',
|
||||||
|
'is_moderator' => true,
|
||||||
|
]);
|
||||||
|
$participant = $room->players()->create([
|
||||||
|
'name' => 'Anna',
|
||||||
|
'is_moderator' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
for ($throwCount = 0; $throwCount < 10; $throwCount++) {
|
||||||
|
$this->withSession(["room_players.{$room->id}" => $participant->id])
|
||||||
|
->postJson(route('room.emote.paper-ball.store', $room), [
|
||||||
|
'target_player_id' => $moderator->id,
|
||||||
|
])
|
||||||
|
->assertNoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->withSession(["room_players.{$room->id}" => $participant->id])
|
||||||
|
->postJson(route('room.emote.paper-ball.store', $room), [
|
||||||
|
'target_player_id' => $moderator->id,
|
||||||
|
])
|
||||||
|
->assertTooManyRequests();
|
||||||
|
|
||||||
|
Event::assertDispatchedTimes(PaperBallThrown::class, 10);
|
||||||
|
});
|
||||||
|
|
||||||
test('a participant cannot throw a paper ball at themselves', function () {
|
test('a participant cannot throw a paper ball at themselves', function () {
|
||||||
Event::fake([PaperBallThrown::class]);
|
Event::fake([PaperBallThrown::class]);
|
||||||
$room = createEmoteRoom();
|
$room = createEmoteRoom();
|
||||||
|
|||||||
Reference in New Issue
Block a user