mirror of
https://github.com/ericasch6/scrum-poker-internal.git
synced 2026-10-13 18:12:09 +00:00
build the backend structure and the fe for the Game
This commit is contained in:
@@ -1,11 +1,150 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\StoreRoomRequest;
|
||||
use App\Models\Deck;
|
||||
use App\Models\Player;
|
||||
use App\Models\Room;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Inertia\Inertia;
|
||||
|
||||
class RoomController extends Controller
|
||||
{
|
||||
public function create(){
|
||||
return Inertia::render('rooms/CreateRoom');
|
||||
public function create(Request $request)
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
$decks = Deck::query()
|
||||
->where(function ($query) use ($user) {
|
||||
$query->where('is_system', true);
|
||||
|
||||
if ($user !== null) {
|
||||
$query->orWhere('user_id', $user->id);
|
||||
}
|
||||
})
|
||||
->orderBy('name')
|
||||
->get([
|
||||
'id',
|
||||
'name',
|
||||
'cards',
|
||||
]);
|
||||
|
||||
return Inertia::render('rooms/Create', [
|
||||
'decks' => $decks,
|
||||
'defaultPlayerName' => $user?->name,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request, StoreRoomRequest $roomStoreRequest)
|
||||
{
|
||||
$validated = $roomStoreRequest->validated();
|
||||
$user = $request->user();
|
||||
|
||||
$deck = Deck::query()
|
||||
->whereKey($validated['deck_id'])
|
||||
->where(function ($query) use ($user) {
|
||||
$query->where('is_system', true);
|
||||
|
||||
if ($user !== null) {
|
||||
$query->orWhere('user_id', $user->id);
|
||||
}
|
||||
})
|
||||
->firstOrFail();
|
||||
|
||||
[$room, $player] = DB::transaction(function () use (
|
||||
$validated,
|
||||
$deck,
|
||||
$user,
|
||||
) {
|
||||
$room = Room::create([
|
||||
'title' => $validated['title'] ?? null,
|
||||
'deck_config' => [
|
||||
'id' => $deck->id,
|
||||
'name' => $deck->name,
|
||||
'cards' => $deck->cards,
|
||||
],
|
||||
]);
|
||||
|
||||
$player = $room->players()->create([
|
||||
'user_id' => $user?->id,
|
||||
'name' => $validated['player_name'],
|
||||
'is_moderator' => true,
|
||||
'last_seen_at' => now(),
|
||||
]);
|
||||
|
||||
return [$room, $player];
|
||||
});
|
||||
|
||||
$request->session()->put(
|
||||
"room_players.{$room->id}",
|
||||
$player->id,
|
||||
);
|
||||
|
||||
return to_route('room.show', $room);
|
||||
}
|
||||
|
||||
public function show(Room $room, Request $request)
|
||||
{
|
||||
$currentPlayer = $request->attributes->get('currentPlayer');
|
||||
|
||||
abort_unless($currentPlayer instanceof Player, 403);
|
||||
|
||||
$room->load([
|
||||
'players' => fn ($query) => $query
|
||||
->select(['id', 'room_id', 'name', 'is_moderator', 'created_at'])
|
||||
->orderByDesc('is_moderator')
|
||||
->orderBy('created_at'),
|
||||
'players.votes' => fn ($query) => $query
|
||||
->where('room_id', $room->id)
|
||||
->where('round', $room->current_round),
|
||||
]);
|
||||
|
||||
$players = $room->players->map(function (Player $player) use ($room) {
|
||||
$vote = $player->votes->first();
|
||||
|
||||
return [
|
||||
'id' => $player->id,
|
||||
'name' => $player->name,
|
||||
'is_moderator' => $player->is_moderator,
|
||||
'has_voted' => $vote !== null,
|
||||
'vote' => $room->revealed_at !== null ? $vote?->value : null,
|
||||
];
|
||||
});
|
||||
|
||||
$currentVote = $room->players
|
||||
->firstWhere('id', $currentPlayer->id)
|
||||
?->votes
|
||||
->first();
|
||||
|
||||
return Inertia::render('rooms/Show', [
|
||||
'room' => [
|
||||
'id' => $room->id,
|
||||
'title' => $room->title,
|
||||
'join_code' => $room->join_code,
|
||||
'current_round' => $room->current_round,
|
||||
'revealed' => $room->revealed_at !== null,
|
||||
'state_version' => $room->state_version,
|
||||
'deck' => [
|
||||
'name' => $room->deck_config['name'],
|
||||
'cards' => $room->deck_config['cards'],
|
||||
],
|
||||
'players' => $players,
|
||||
],
|
||||
'currentPlayer' => [
|
||||
'id' => $currentPlayer->id,
|
||||
'name' => $currentPlayer->name,
|
||||
'is_moderator' => $currentPlayer->is_moderator,
|
||||
'current_vote' => $currentVote?->value,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function join(Request $request)
|
||||
{
|
||||
return Inertia::render('rooms/Join', [
|
||||
'join_code' => $request->query('join_code'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\JoinRoomRequest;
|
||||
use App\Models\Room;
|
||||
|
||||
class RoomPlayerController extends Controller
|
||||
{
|
||||
public function join(JoinRoomRequest $request)
|
||||
{
|
||||
$validated = $request->validated();
|
||||
$user = $request->user();
|
||||
|
||||
$room = Room::where('join_code', '=', $validated['join_code'])->firstOrFail();
|
||||
|
||||
$player = $room->players()->create([
|
||||
'user_id' => $user?->id,
|
||||
'name' => $validated['player_name'],
|
||||
'is_moderator' => false,
|
||||
'last_seen_at' => now(),
|
||||
]);
|
||||
|
||||
$request->session()->put(
|
||||
"room_players.{$room->id}",
|
||||
$player->id,
|
||||
);
|
||||
|
||||
return to_route('room.show', $room);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Player;
|
||||
use App\Models\Room;
|
||||
use App\Models\Vote;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class RoundController extends Controller
|
||||
{
|
||||
public function reset(
|
||||
Request $request,
|
||||
Room $room,
|
||||
): RedirectResponse {
|
||||
$player = $request->attributes->get('currentPlayer');
|
||||
|
||||
abort_unless(
|
||||
$player instanceof Player
|
||||
&& $player->room_id === $room->id
|
||||
&& $player->is_moderator,
|
||||
403,
|
||||
);
|
||||
|
||||
DB::transaction(function () use ($room) {
|
||||
$lockedRoom = Room::query()
|
||||
->lockForUpdate()
|
||||
->findOrFail($room->id);
|
||||
|
||||
Vote::query()
|
||||
->where('room_id', $lockedRoom->id)
|
||||
->where('round', $lockedRoom->current_round)
|
||||
->delete();
|
||||
|
||||
$lockedRoom->update([
|
||||
'revealed_at' => null,
|
||||
'state_version' => $lockedRoom->state_version + 1,
|
||||
]);
|
||||
});
|
||||
|
||||
return back();
|
||||
}
|
||||
|
||||
public function reveal(
|
||||
Request $request,
|
||||
Room $room,
|
||||
): RedirectResponse {
|
||||
$player = $request->attributes->get('currentPlayer');
|
||||
|
||||
abort_unless(
|
||||
$player instanceof Player
|
||||
&& $player->room_id === $room->id
|
||||
&& $player->is_moderator,
|
||||
403,
|
||||
);
|
||||
|
||||
DB::transaction(function () use ($room) {
|
||||
$lockedRoom = Room::query()
|
||||
->lockForUpdate()
|
||||
->findOrFail($room->id);
|
||||
|
||||
if ($lockedRoom->revealed_at !== null) {
|
||||
throw ValidationException::withMessages([
|
||||
'room' => 'Die Karten sind bereits aufgedeckt.',
|
||||
]);
|
||||
}
|
||||
|
||||
$lockedRoom->update([
|
||||
'revealed_at' => now(),
|
||||
'state_version' => $lockedRoom->state_version + 1,
|
||||
]);
|
||||
});
|
||||
|
||||
return back();
|
||||
}
|
||||
|
||||
public function nextRound(
|
||||
Request $request,
|
||||
Room $room,
|
||||
): RedirectResponse {
|
||||
$player = $request->attributes->get('currentPlayer');
|
||||
|
||||
abort_unless(
|
||||
$player instanceof Player
|
||||
&& $player->room_id === $room->id
|
||||
&& $player->is_moderator,
|
||||
403,
|
||||
);
|
||||
|
||||
DB::transaction(function () use ($room) {
|
||||
$lockedRoom = Room::query()
|
||||
->lockForUpdate()
|
||||
->findOrFail($room->id);
|
||||
|
||||
if ($lockedRoom->revealed_at === null) {
|
||||
throw ValidationException::withMessages([
|
||||
'room' => 'Die aktuelle Runde muss zuerst aufgedeckt werden.',
|
||||
]);
|
||||
}
|
||||
|
||||
$lockedRoom->update([
|
||||
'current_round' => $lockedRoom->current_round + 1,
|
||||
'revealed_at' => null,
|
||||
'state_version' => $lockedRoom->state_version + 1,
|
||||
]);
|
||||
});
|
||||
|
||||
return back();
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,55 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Requests\SubmitVoteRequest;
|
||||
use App\Models\Player;
|
||||
use App\Models\Room;
|
||||
use App\Models\Vote;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class VoteController extends Controller
|
||||
{
|
||||
//
|
||||
public function store(
|
||||
SubmitVoteRequest $request,
|
||||
Room $room,
|
||||
): RedirectResponse {
|
||||
$player = $request->attributes->get('currentPlayer');
|
||||
|
||||
abort_unless(
|
||||
$player instanceof Player
|
||||
&& $player->room_id === $room->id,
|
||||
403,
|
||||
);
|
||||
|
||||
$value = $request->validated('value');
|
||||
|
||||
DB::transaction(function () use ($room, $player, $value) {
|
||||
$lockedRoom = Room::query()
|
||||
->lockForUpdate()
|
||||
->findOrFail($room->id);
|
||||
|
||||
if ($lockedRoom->revealed_at !== null) {
|
||||
throw ValidationException::withMessages([
|
||||
'value' => 'Die Karten wurden bereits aufgedeckt.',
|
||||
]);
|
||||
}
|
||||
|
||||
Vote::updateOrCreate(
|
||||
[
|
||||
'room_id' => $lockedRoom->id,
|
||||
'player_id' => $player->id,
|
||||
'round' => $lockedRoom->current_round,
|
||||
],
|
||||
[
|
||||
'value' => $value,
|
||||
],
|
||||
);
|
||||
|
||||
$lockedRoom->increment('state_version');
|
||||
});
|
||||
|
||||
return back();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user