mirror of
https://github.com/ericasch6/scrum-poker-internal.git
synced 2026-10-13 22:32:08 +00:00
allow anyone controll room option
This commit is contained in:
@@ -9,6 +9,7 @@ enum RoomStateChange: string
|
||||
case CardsRevealed = 'cards_revealed';
|
||||
case VotesReset = 'votes_reset';
|
||||
case NextRound = 'next_round';
|
||||
case PermissionsUpdated = 'permissions_updated';
|
||||
case RoomReopened = 'room_reopened';
|
||||
case RoomClosed = 'room_closed';
|
||||
case RoomDeleted = 'room_deleted';
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\UpdateRoomPermissionsRequest;
|
||||
use App\Models\Room;
|
||||
use App\Services\Rooms\RoomPermissionService;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class RoomPermissionController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly RoomPermissionService $roomPermissions,
|
||||
) {}
|
||||
|
||||
public function __invoke(UpdateRoomPermissionsRequest $request, Room $room): Response
|
||||
{
|
||||
$this->roomPermissions->updateParticipantControls(
|
||||
$room,
|
||||
(bool) $request->validated('allow_participant_controls'),
|
||||
);
|
||||
|
||||
return response()->noContent();
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ class RoundController extends Controller
|
||||
|
||||
public function reset(Request $request, Room $room): Response
|
||||
{
|
||||
$this->ensureModerator($request, $room);
|
||||
$this->ensureCanControlRound($request, $room);
|
||||
$this->rounds->reset($room);
|
||||
|
||||
return response()->noContent();
|
||||
@@ -24,7 +24,7 @@ class RoundController extends Controller
|
||||
|
||||
public function reveal(Request $request, Room $room): Response
|
||||
{
|
||||
$this->ensureModerator($request, $room);
|
||||
$this->ensureCanControlRound($request, $room);
|
||||
$this->rounds->reveal($room);
|
||||
|
||||
return response()->noContent();
|
||||
@@ -32,20 +32,20 @@ class RoundController extends Controller
|
||||
|
||||
public function nextRound(Request $request, Room $room): Response
|
||||
{
|
||||
$this->ensureModerator($request, $room);
|
||||
$this->ensureCanControlRound($request, $room);
|
||||
$this->rounds->startNext($room);
|
||||
|
||||
return response()->noContent();
|
||||
}
|
||||
|
||||
private function ensureModerator(Request $request, Room $room): void
|
||||
private function ensureCanControlRound(Request $request, Room $room): void
|
||||
{
|
||||
$player = $request->attributes->get('currentPlayer');
|
||||
|
||||
abort_unless(
|
||||
$player instanceof Player
|
||||
&& $player->room_id === $room->id
|
||||
&& $player->is_moderator,
|
||||
&& ($player->is_moderator || $room->allow_participant_controls),
|
||||
403,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Player;
|
||||
use App\Models\Room;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UpdateRoomPermissionsRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
$room = $this->route('room');
|
||||
$player = $this->attributes->get('currentPlayer');
|
||||
|
||||
return $room instanceof Room
|
||||
&& $player instanceof Player
|
||||
&& $player->room_id === $room->id
|
||||
&& $player->is_moderator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'allow_participant_controls' => ['required', 'boolean:strict'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ class RoomResource extends JsonResource
|
||||
'current_round' => $room->current_round,
|
||||
'revealed' => $room->revealed_at !== null,
|
||||
'state_version' => $room->state_version,
|
||||
'allow_participant_controls' => $room->allow_participant_controls,
|
||||
'statistics' => $pageData->statistics,
|
||||
'deck' => (new RoomDeckResource($room->deck_config))->resolve($request),
|
||||
'players' => $room->players
|
||||
|
||||
@@ -19,6 +19,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @property int $current_round
|
||||
* @property CarbonImmutable|null $revealed_at
|
||||
* @property int $state_version
|
||||
* @property bool $allow_participant_controls
|
||||
* @property CarbonImmutable|null $last_activity_at
|
||||
* @property CarbonImmutable|null $closed_at
|
||||
* @property CarbonImmutable|null $deleted_at
|
||||
@@ -35,6 +36,7 @@ class Room extends Model
|
||||
'deck_config',
|
||||
'revealed_at',
|
||||
'state_version',
|
||||
'allow_participant_controls',
|
||||
'last_activity_at',
|
||||
'closed_at',
|
||||
];
|
||||
@@ -44,6 +46,7 @@ class Room extends Model
|
||||
return [
|
||||
'current_round' => 'integer',
|
||||
'state_version' => 'integer',
|
||||
'allow_participant_controls' => 'boolean',
|
||||
'revealed_at' => 'immutable_datetime',
|
||||
'last_activity_at' => 'immutable_datetime',
|
||||
'closed_at' => 'immutable_datetime',
|
||||
@@ -51,6 +54,10 @@ class Room extends Model
|
||||
];
|
||||
}
|
||||
|
||||
protected $attributes = [
|
||||
'allow_participant_controls' => false,
|
||||
];
|
||||
|
||||
protected static function booted(): void
|
||||
{
|
||||
static::creating(function (Room $room) {
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Rooms;
|
||||
|
||||
use App\Enums\RoomStateChange;
|
||||
use App\Events\RoomStateChanged;
|
||||
use App\Models\Room;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class RoomPermissionService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly RoomRealtimeStateService $realtimeState,
|
||||
) {}
|
||||
|
||||
public function updateParticipantControls(Room $room, bool $allowParticipantControls): void
|
||||
{
|
||||
[$stateVersion, $wasChanged] = DB::transaction(function () use ($room, $allowParticipantControls): array {
|
||||
$lockedRoom = Room::query()
|
||||
->lockForUpdate()
|
||||
->findOrFail($room->id);
|
||||
|
||||
if ($lockedRoom->allow_participant_controls === $allowParticipantControls) {
|
||||
return [$lockedRoom->state_version, false];
|
||||
}
|
||||
|
||||
$lockedRoom->update([
|
||||
'allow_participant_controls' => $allowParticipantControls,
|
||||
'last_activity_at' => now(),
|
||||
'state_version' => $lockedRoom->state_version + 1,
|
||||
]);
|
||||
|
||||
return [$lockedRoom->state_version, true];
|
||||
});
|
||||
|
||||
if (! $wasChanged) {
|
||||
return;
|
||||
}
|
||||
|
||||
RoomStateChanged::dispatch(
|
||||
$room->id,
|
||||
$stateVersion,
|
||||
RoomStateChange::PermissionsUpdated,
|
||||
$this->realtimeState->for($room),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ class RoomRealtimeStateService
|
||||
* current_round: int,
|
||||
* revealed: bool,
|
||||
* state_version: int,
|
||||
* allow_participant_controls: bool,
|
||||
* statistics: array{average: string|null, median: string|null}|null,
|
||||
* players: array<int, array{
|
||||
* id: int,
|
||||
@@ -44,6 +45,7 @@ class RoomRealtimeStateService
|
||||
'current_round' => $room->current_round,
|
||||
'revealed' => $room->revealed_at !== null,
|
||||
'state_version' => $room->state_version,
|
||||
'allow_participant_controls' => $room->allow_participant_controls,
|
||||
'statistics' => $this->statistics->currentRound($room),
|
||||
'players' => $room->players
|
||||
->map(function ($player) use ($room): array {
|
||||
|
||||
Reference in New Issue
Block a user