From cf238d54519ecfa20619780547448307575727f0 Mon Sep 17 00:00:00 2001 From: Tiago Ramos <2222055@my.ipleiria.pt> Date: Wed, 31 Dec 2025 15:48:24 +0000 Subject: [PATCH] Added api logic with transactions when match is finished, started and joined --- api/app/Http/Controllers/GameController.php | 2 - api/app/Http/Controllers/MatchController.php | 155 +++++++++++++------ 2 files changed, 110 insertions(+), 47 deletions(-) diff --git a/api/app/Http/Controllers/GameController.php b/api/app/Http/Controllers/GameController.php index 886243e..5590763 100644 --- a/api/app/Http/Controllers/GameController.php +++ b/api/app/Http/Controllers/GameController.php @@ -4,9 +4,7 @@ namespace App\Http\Controllers; use App\Models\Game; use Illuminate\Http\Request; -use App\Http\Requests\StoreGameRequest; use Illuminate\Support\Facades\Auth; -use App\Models\MatchGame; class GameController extends Controller { diff --git a/api/app/Http/Controllers/MatchController.php b/api/app/Http/Controllers/MatchController.php index 09f5c39..fe6972f 100644 --- a/api/app/Http/Controllers/MatchController.php +++ b/api/app/Http/Controllers/MatchController.php @@ -4,12 +4,15 @@ namespace App\Http\Controllers; use App\Models\MatchGame; use App\Models\Game; +use App\Models\CoinTransaction; +use App\Models\CoinTransactionType; use Illuminate\Http\Request; use App\Http\Requests\StoreMatchRequest; use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\DB; class MatchController extends Controller -{ +{ public function index(Request $request) { $query = MatchGame::query()->with(['winner', 'player1', 'player2']); @@ -28,44 +31,61 @@ class MatchController extends Controller } public function store(StoreMatchRequest $request) - { + { $validated = $request->validated(); - $user = Auth::user(); + $user = $request->user(); + $stake = $validated['stake']; + + if ($user->coins_balance < $stake) { + return response()->json(['message' => 'Insufficient coin balance'], 400); + } $activeMatch = MatchGame::where(function ($q) use ($user) { $q->where('player1_user_id', $user->id) ->orWhere('player2_user_id', $user->id); })->whereIn('status', ['Pending', 'Playing'])->exists(); - $activeGame = Game::where(function ($q) use ($user) { - $q->where('player1_user_id', $user->id) - ->orWhere('player2_user_id', $user->id); - })->whereIn('status', ['Pending', 'Playing'])->exists(); - - if ($activeMatch || $activeGame) { - return response()->json(['message' => 'You already have an active game or match.'], 400); + if ($activeMatch) { + return response()->json(['message' => 'You already have an active match.'], 400); } - $match = MatchGame::create([ - 'type' => $validated['type'], - 'status' => 'Pending', - 'player1_user_id' => $user->id, - 'player2_user_id' => $user->id, - 'winner_user_id' => $user->id, - 'loser_user_id' => $user->id, - 'stake' => $validated['stake'], - 'began_at' => now(), - 'player1_marks' => 0, - 'player2_marks' => 0, - 'player1_points' => 0, - 'player2_points' => 0, - 'custom' => null - ]); + return DB::transaction(function () use ($validated, $user, $stake) { + $GHOST_ID = 1; - return response()->json([ - 'message' => 'Match created successfully', - 'match' => $match - ], 201); + $user->decrement('coins_balance', $stake); + + $stakeType = CoinTransactionType::firstOrCreate( + ['name' => 'Match stake'], + ['type' => 'D'] // Debit + ); + + $match = MatchGame::create([ + 'type' => $validated['type'], + 'status' => 'Pending', + 'player1_user_id' => $user->id, + 'player2_user_id' => $GHOST_ID, + 'winner_user_id' => $GHOST_ID, + 'loser_user_id' => $GHOST_ID, + 'stake' => $stake, + 'began_at' => now(), + 'player1_marks' => 0, 'player2_marks' => 0, + 'player1_points' => 0, 'player2_points' => 0, + ]); + + CoinTransaction::create([ + 'user_id' => $user->id, + 'match_id' => $match->id, + 'coin_transaction_type_id' => $stakeType->id, + 'transaction_datetime' => now(), + 'coins' => -$stake, + ]); + + return response()->json([ + 'message' => 'Match created successfully', + 'match' => $match, + 'balance' => $user->coins_balance + ], 201); + }); } public function show(MatchGame $match) @@ -76,16 +96,19 @@ class MatchController extends Controller public function join(MatchGame $match) { - $user = Auth::user(); + $user = request()->user(); if ($match->player1_user_id == $user->id) { - return response()->json(['message' => 'Waiting for opponent...', 'match' => $match]); + return response()->json(['message' => 'You cannot join your own match'], 400); } - if ($match->status !== 'Pending') { return response()->json(['message' => 'Match is full or started'], 400); } + if ($user->coins_balance < $match->stake) { + return response()->json(['message' => 'Insufficient coin balance to join this match'], 400); + } + $activeMatch = MatchGame::where(function ($q) use ($user) { $q->where('player1_user_id', $user->id) ->orWhere('player2_user_id', $user->id); @@ -95,15 +118,33 @@ class MatchController extends Controller return response()->json(['message' => 'You are already in another active match.'], 400); } - $match->update([ - 'status' => 'Playing', - 'player2_user_id' => $user->id - ]); + return DB::transaction(function () use ($match, $user) { + $user->decrement('coins_balance', $match->stake); - return response()->json([ - 'message' => 'Joined match successfully!', - 'match' => $match - ]); + $stakeType = CoinTransactionType::firstOrCreate( + ['name' => 'Match stake'], + ['type' => 'D'] + ); + + CoinTransaction::create([ + 'user_id' => $user->id, + 'match_id' => $match->id, + 'coin_transaction_type_id' => $stakeType->id, + 'transaction_datetime' => now(), + 'coins' => -$match->stake, + ]); + + $match->update([ + 'status' => 'Playing', + 'player2_user_id' => $user->id + ]); + + return response()->json([ + 'message' => 'Joined match successfully!', + 'match' => $match, + 'balance' => $user->coins_balance + ]); + }); } public function update(Request $request, MatchGame $match) @@ -123,12 +164,36 @@ class MatchController extends Controller 'total_time' => 'numeric' ]); - if (isset($data['status']) && $data['status'] === 'Ended') { - $data['ended_at'] = now(); - } + return DB::transaction(function () use ($match, $data) { + + if (isset($data['status']) && $data['status'] === 'Ended') { + $data['ended_at'] = now(); + } - $match->update($data); + $match->update($data); - return response()->json($match); + if ($match->status === 'Ended' && $match->stake > 0 && $match->winner_user_id) { + + $payoutType = CoinTransactionType::firstOrCreate( + ['name' => 'Match payout'], + ['type' => 'C'] // Credit + ); + + $totalPrize = $match->stake * 2; + + CoinTransaction::create([ + 'user_id' => $match->winner_user_id, + 'match_id' => $match->id, + 'coin_transaction_type_id' => $payoutType->id, + 'transaction_datetime' => now(), + 'coins' => $totalPrize, + ]); + + + $match->winner->increment('coins_balance', $totalPrize); + } + + return response()->json($match); + }); } } \ No newline at end of file -- 2.54.0